]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
API change for expunging messages. Not exactly what I wanted, but good
authorTimo Sirainen <tss@iki.fi>
Sat, 26 Jul 2003 16:33:21 +0000 (19:33 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 26 Jul 2003 16:33:21 +0000 (19:33 +0300)
enough.

--HG--
branch : HEAD

21 files changed:
src/imap/Makefile.am
src/imap/cmd-close.c
src/imap/cmd-expunge.c
src/lib-index/mail-index.c
src/lib-index/mail-index.h
src/lib-storage/index/index-expunge.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-mail.h
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-storage.h
src/lib-storage/index/index-update-flags.c
src/lib-storage/index/maildir/maildir-expunge.c
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/maildir/maildir-storage.h
src/lib-storage/index/mbox/mbox-expunge.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/mbox/mbox-storage.h
src/lib-storage/mail-storage.h
src/pop3/client.c
src/pop3/commands.c
src/pop3/mail-storage-callbacks.c

index 121e03379a33a8b19832a0fd61c738473e67d14b..a63f9eee741ab9d2d0f882f50aa5f863246645f2 100644 (file)
@@ -61,6 +61,7 @@ imap_SOURCES = \
        client.c \
        commands.c \
        commands-util.c \
+       imap-expunge.c \
        imap-fetch.c \
        imap-fetch-body-section.c \
        imap-search.c \
@@ -76,6 +77,7 @@ noinst_HEADERS = \
        commands.h \
        commands-util.h \
        common.h \
+       imap-expunge.h \
        imap-fetch.h \
        imap-search.h \
        imap-sort.h \
index 02a364cd0de3ce29095fcdbfb3d7421df09a6f91..50a541b9f9dbd9790b4db17322b145b5262a30d8 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "commands.h"
+#include "imap-expunge.h"
 
 int cmd_close(struct client *client)
 {
@@ -13,7 +14,7 @@ int cmd_close(struct client *client)
        client->mailbox = NULL;
 
        if (!mailbox->readonly) {
-               if (!mailbox->expunge(mailbox, FALSE))
+               if (!imap_expunge(mailbox, FALSE))
                        client_send_untagged_storage_error(client);
        }
 
index 2e310662b6c27ddda154f884f68343d9132a9021..719efc923f8a190f8250d1bcaa314857e4e10b20 100644 (file)
@@ -2,13 +2,14 @@
 
 #include "common.h"
 #include "commands.h"
+#include "imap-expunge.h"
 
 int cmd_expunge(struct client *client)
 {
        if (!client_verify_open_mailbox(client))
                return TRUE;
 
-       if (client->mailbox->expunge(client->mailbox, TRUE))
+       if (imap_expunge(client->mailbox, TRUE))
                client_send_tagline(client, "OK Expunge completed.");
        else
                client_send_storage_error(client);
index c94ccc56c716a16acdd1da0aa1f507569a7d071a..da28d9eda2cbc5018d914b06c96a6b8ccd17a75c 100644 (file)
@@ -657,29 +657,6 @@ void mail_index_mark_flag_changes(struct mail_index *index,
        }
 }
 
-#if 0
-static int mail_index_truncate_hole(struct mail_index *index)
-{
-       index->header->used_file_size = sizeof(struct mail_index_header) +
-               (uoff_t)index->header->first_hole_index *
-               sizeof(struct mail_index_record);
-       index->header->first_hole_index = 0;
-       index->header->first_hole_records = 0;
-
-       index->mmap_used_length = index->header->used_file_size;
-       if (!mail_index_truncate(index))
-               return FALSE;
-
-       if (index->header->messages_count == 0) {
-               /* all mail was deleted, truncate data file */
-               if (!mail_index_data_reset(index->data))
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-#endif
-
 #define INDEX_NEED_COMPRESS(records, hdr) \
        ((records) > INDEX_MIN_RECORDS_COUNT && \
         (records) * (100-INDEX_COMPRESS_PERCENTAGE) / 100 > \
@@ -697,6 +674,8 @@ int mail_index_expunge(struct mail_index *index,
        i_assert(first_seq != 0);
        i_assert(first_seq <= last_seq);
 
+       index->expunge_counter++;
+
        first_uid = first_rec->uid;
        last_uid = last_rec->uid;
 
@@ -711,6 +690,12 @@ int mail_index_expunge(struct mail_index *index,
                        return FALSE;
        }
 
+       if (index->header->messages_count == 0) {
+               /* all mail was deleted, truncate data file */
+               if (!mail_index_data_reset(index->data))
+                       return FALSE;
+       }
+
        return TRUE;
 }
 
index 78ce3fa53ccbb7b911fab68d8179b7475b61442f..bab2fa5d60d3ee247996be57d609cc63b2979bc3 100644 (file)
@@ -385,6 +385,8 @@ struct mail_index {
 
         /* updated whenever exclusive lock is set/unset */
        unsigned int excl_lock_counter;
+       /* updated whenever expunge() is called */
+       unsigned int expunge_counter;
 
        int mbox_fd;
        struct istream *mbox_stream;
@@ -454,11 +456,11 @@ struct mail_index {
    members.. */
 #define MAIL_INDEX_PRIVATE_FILL \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-       0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, \
+       0, 0, 0, 0, 0, 0, { 0, 0, 0 }, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-       0, 0, 0, 0, 0, 0
+       0, 0, 0, 0, 0, 0, 0
 #endif
 
 /* defaults - same as above but prefixed with mail_index_. */
index 7a7771f9f06e3a41bc15d9a4de3734e3af7306a2..da9c0d2cc7415d3c1336ce89fc8b1843d7f8e893 100644 (file)
@@ -1,10 +1,12 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
 #include "index-storage.h"
+#include "index-expunge.h"
 
-int index_expunge_seek_first(struct index_mailbox *ibox, unsigned int *seq,
-                            struct mail_index_record **rec)
+static int index_expunge_seek_first(struct index_mailbox *ibox,
+                                   unsigned int *seq,
+                                   struct mail_index_record **rec)
 {
        struct mail_index_header *hdr;
 
@@ -43,70 +45,156 @@ int index_expunge_seek_first(struct index_mailbox *ibox, unsigned int *seq,
        return TRUE;
 }
 
-int index_expunge_mails(struct index_mailbox *ibox,
-                       struct mail_index_record *first_rec,
-                       struct mail_index_record *last_rec,
-                       unsigned int first_seq, unsigned int last_seq,
-                       int notify)
+struct mail_expunge_context *
+index_storage_expunge_init(struct mailbox *box,
+                          enum mail_fetch_field wanted_fields,
+                          int expunge_all)
 {
-       unsigned int max;
+       struct index_mailbox *ibox = (struct index_mailbox *) box;
+       struct mail_expunge_context *ctx;
 
-       if (!ibox->index->expunge(ibox->index, first_rec, last_rec,
-                                 first_seq, last_seq, FALSE))
-               return FALSE;
+       if (box->readonly) {
+               box->storage->callbacks->
+                       notify_no(box, "Mailbox is read-only, ignoring expunge",
+                                 box->storage->callback_context);
+               return i_new(struct mail_expunge_context, 1);
+       }
 
-       if (first_seq > ibox->synced_messages_count)
-               return TRUE;
+       if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
+               return NULL;
+
+       ctx = i_new(struct mail_expunge_context, 1);
+       ctx->ibox = ibox;
+       ctx->expunge_all = expunge_all;
+       index_mail_init(ibox, &ctx->mail, wanted_fields, NULL);
+
+       do {
+               if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
+                                                MAIL_LOCK_EXCLUSIVE))
+                       break;
+
+               /* modifylog must be marked synced before expunging
+                  anything new */
+               if (!index_storage_sync_modifylog(ibox, TRUE))
+                       break;
+
+               if (expunge_all) {
+                       ctx->seq = 1;
+                       ctx->rec = ibox->index->lookup(ibox->index, 1);
+               } else {
+                       if (!index_expunge_seek_first(ibox, &ctx->seq,
+                                                     &ctx->rec))
+                               break;
+
+                       ctx->fetch_next = ctx->rec != NULL &&
+                               (ctx->rec->msg_flags & MAIL_DELETED) == 0;
+               }
 
-       max = last_seq > ibox->synced_messages_count ?
-               ibox->synced_messages_count : last_seq;
+               return ctx;
+       } while (0);
 
-       ibox->synced_messages_count -= max - first_seq + 1;
-       if (notify) {
-               struct mail_storage_callbacks *cb;
-               void *cb_ctx;
+       (void)index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK);
+       i_free(ctx);
+       return NULL;
+}
 
-               cb = ibox->box.storage->callbacks;
-               cb_ctx = ibox->box.storage->callback_context;
+int index_storage_expunge_deinit(struct mail_expunge_context *ctx)
+{
+       int ret = !ctx->failed;
+
+       if (ctx->first_seq != 0) {
+               if (!ctx->ibox->index->expunge(ctx->ibox->index,
+                                              ctx->first_rec, ctx->last_rec,
+                                              ctx->first_seq, ctx->last_seq,
+                                              FALSE))
+                       ret = FALSE;
+       }
 
-               while (max >= first_seq) {
-                       cb->expunge(&ibox->box, first_seq, cb_ctx);
-                       max--;
-               }
+       if (ctx->ibox != NULL) {
+               ctx->ibox->fetch_mail.data.rec = NULL;
+
+               if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK))
+                       ret = FALSE;
        }
 
-       return TRUE;
+       i_free(ctx);
+       return ret;
 }
 
-int index_storage_expunge(struct mailbox *box, int notify)
+struct mail *index_storage_expunge_fetch_next(struct mail_expunge_context *ctx)
 {
-       struct index_mailbox *ibox = (struct index_mailbox *) box;
-       int failed;
+       struct mail_index *index = ctx->ibox->index;
+
+       if (ctx->rec == NULL)
+               return NULL;
+
+       if (ctx->fetch_next) {
+               do {
+                       ctx->seq++;
+                       ctx->rec = index->next(index, ctx->rec);
+                       if (ctx->rec == NULL)
+                               return NULL;
+               } while ((ctx->rec->msg_flags & MAIL_DELETED) == 0 &&
+                        !ctx->expunge_all);
+       } else {
+               ctx->fetch_next = TRUE;
+       }
 
-       if (box->readonly) {
-               box->storage->callbacks->
-                       notify_no(&ibox->box,
-                                 "Mailbox is read-only, ignoring expunge",
-                                 box->storage->callback_context);
-               return TRUE;
+       ctx->mail.expunge_counter = index->expunge_counter;
+       ctx->mail.mail.seq = ctx->seq;
+       ctx->mail.mail.uid = ctx->rec->uid;
+
+       if (!index_mail_next(&ctx->mail, ctx->rec, ctx->seq)) {
+               ctx->failed = TRUE;
+               return NULL;
        }
 
-       if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
-               return FALSE;
+       return &ctx->mail.mail;
+}
+
+int index_storage_expunge(struct mail *mail, struct mail_expunge_context *ctx,
+                         unsigned int *seq_r, int notify)
+{
+       struct index_mail *imail = (struct index_mail *) mail;
+       struct index_mailbox *ibox = imail->ibox;
+       unsigned int seq;
+
+       /* currently we allow expunges only from beginning to end so we can
+          easily update sequence numbers */
+       i_assert(ctx->last_seq < ctx->seq);
+
+       seq = mail->seq;
+       if (ctx->first_seq != 0)
+               seq -= (ctx->last_seq - ctx->first_seq) + 1;
+       if (seq_r != NULL) *seq_r = seq;
+
+       if (ctx->first_seq != 0 && ctx->seq != ctx->last_seq+1) {
+               if (!ibox->index->expunge(ibox->index,
+                                         ctx->first_rec, ctx->last_rec,
+                                         ctx->first_seq, ctx->last_seq, FALSE))
+                       return FALSE;
+
+               ctx->seq -= (ctx->last_seq - ctx->first_seq) + 1;
+               ctx->rec = ibox->index->lookup(ibox->index, ctx->seq);
+
+               ctx->first_seq = 0;
+       }
 
-       if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
-                                        MAIL_LOCK_EXCLUSIVE))
-               return FALSE;
+       if (ctx->first_seq == 0) {
+               ctx->first_seq = ctx->seq;
+               ctx->first_rec = ctx->rec;
+       }
+       ctx->last_seq = ctx->seq;
+       ctx->last_rec = ctx->rec;
 
-       /* modifylog must be marked synced before expunging
-          anything new */
-       if (!index_storage_sync_modifylog(ibox, TRUE))
-               failed = TRUE;
-       else
-               failed = !ibox->expunge_locked(ibox, notify);
+       ibox->fetch_mail.data.rec = NULL;
 
-       if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK))
-               return FALSE;
+       ibox->synced_messages_count--;
+       if (notify && seq <= ibox->synced_messages_count+1) {
+               ibox->box.storage->callbacks->
+                       expunge(&ibox->box, seq,
+                               ibox->box.storage->callback_context);
+       }
 
-       return !failed;
+       return TRUE;
 }
index faf36a3301a15eb28b0c78e9ce0c3bcbdb60e71f..e4b2452696dbdb0a1a9dc4332a71e4e767a43611 100644 (file)
@@ -12,6 +12,7 @@
 #include "mail-index-util.h"
 #include "mail-custom-flags.h"
 #include "index-storage.h"
+#include "index-expunge.h"
 #include "index-mail.h"
 
 #include <ctype.h>
@@ -650,7 +651,8 @@ static struct mail index_mail = {
        get_stream,
        get_special,
        index_storage_update_flags,
-       index_storage_copy
+       index_storage_copy,
+       index_storage_expunge
 };
 
 void index_mail_init(struct index_mailbox *ibox, struct index_mail *mail,
@@ -664,6 +666,7 @@ void index_mail_init(struct index_mailbox *ibox, struct index_mail *mail,
        mail->ibox = ibox;
        mail->wanted_fields = wanted_fields;
        mail->wanted_headers = wanted_headers;
+       mail->expunge_counter = ibox->index->expunge_counter;
 
        if (ibox->mail_init != NULL)
                ibox->mail_init(mail);
@@ -675,6 +678,8 @@ int index_mail_next(struct index_mail *mail, struct mail_index_record *rec,
        struct index_mail_data *data = &mail->data;
        int ret, open_mail, parse_header, envelope_headers;
 
+       i_assert(mail->expunge_counter == mail->ibox->index->expunge_counter);
+
        t_push();
 
        /* close the old one */
index 609cdbc2b46f0a96e855125a74efd51eb8d80d64..2396b2b31e315f91df9f41487d8e4cc5278d20b9 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef __INDEX_MAIL_H
 #define __INDEX_MAIL_H
 
+#include "message-size.h"
+
+struct message_header_line;
+
 struct cached_header {
        struct cached_header *next;
 
@@ -40,6 +44,7 @@ struct index_mail {
 
        pool_t pool;
        struct index_mailbox *ibox;
+       unsigned int expunge_counter;
        buffer_t *header_buf;
 
        enum mail_fetch_field wanted_fields;
index efd4c000221c500b41a6b52c84ae9932fce012ff..0bd23fe9fae8446becdea6a12babca4738da6758 100644 (file)
@@ -288,7 +288,7 @@ int index_storage_lock(struct index_mailbox *ibox,
                if (ibox->lock_type != MAILBOX_LOCK_UNLOCK)
                        return TRUE;
        } else {
-               if (ibox->index->lock_type == MAIL_LOCK_EXCLUSIVE)
+               if (ibox->lock_type == MAIL_LOCK_EXCLUSIVE)
                        return TRUE;
        }
 
index afb72670cd21a3cc1590542de144121de3afa812..be044734ee9c48ccdd1c3ef6937d1c2a4ac8a178 100644 (file)
@@ -17,7 +17,6 @@ struct index_mailbox {
 
        /* expunge messages marked as deleted, requires index to be
           exclusively locked */
-       int (*expunge_locked)(struct index_mailbox *ibox, int notify);
        void (*mail_init)(struct index_mail *mail);
 
        struct mail_index *index;
@@ -36,6 +35,7 @@ struct index_mailbox {
        enum mail_lock_notify_type last_notify_type;
 
        unsigned int sent_diskspace_warning:1;
+       unsigned int sent_readonly_flags_warning:1;
 };
 
 int mail_storage_set_index_error(struct index_mailbox *ibox);
@@ -69,14 +69,6 @@ int index_mailbox_fix_custom_flags(struct index_mailbox *ibox,
 
 unsigned int index_storage_get_recent_count(struct mail_index *index);
 
-int index_expunge_seek_first(struct index_mailbox *ibox, unsigned int *seq,
-                            struct mail_index_record **rec);
-int index_expunge_mails(struct index_mailbox *ibox,
-                       struct mail_index_record *first_rec,
-                       struct mail_index_record *last_rec,
-                       unsigned int first_seq, unsigned int last_seq,
-                       int notify);
-
 void index_mailbox_check_add(struct index_mailbox *ibox, const char *path);
 void index_mailbox_check_remove_all(struct index_mailbox *ibox);
 
@@ -84,7 +76,6 @@ void index_mailbox_check_remove_all(struct index_mailbox *ibox);
 void index_storage_set_callbacks(struct mail_storage *storage,
                                 struct mail_storage_callbacks *callbacks,
                                 void *context);
-int index_storage_expunge(struct mailbox *box, int notify);
 int index_storage_get_status(struct mailbox *box,
                             enum mailbox_status_items items,
                             struct mailbox_status *status);
index 34d5c1a5447cef679e0938b738db576253b29991..87aacc1ab44459540c83d10497772d3e64997712 100644 (file)
@@ -15,6 +15,10 @@ int index_storage_update_flags(struct mail *mail,
        enum mail_flags modify_flags, new_flags;
 
        if (mail->box->readonly) {
+               if (ibox->sent_readonly_flags_warning)
+                       return TRUE;
+                ibox->sent_readonly_flags_warning = TRUE;
+
                storage->callbacks->
                        notify_no(&ibox->box,
                                  "Mailbox is read-only, ignoring flag changes",
index b28f0f471e786806fcc56befdc73d5ef58807515..f9a8699a28a727bfc404c44c606859999a3be20e 100644 (file)
@@ -1,67 +1,83 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
+#include "index-expunge.h"
 #include "maildir-index.h"
 #include "maildir-storage.h"
 
-int maildir_expunge_locked(struct index_mailbox *ibox, int notify)
+struct maildir_expunge_context {
+       struct mail_expunge_context *ctx;
+       int sent_access_warning;
+};
+
+struct mail_expunge_context *
+maildir_storage_expunge_init(struct mailbox *box,
+                            enum mail_fetch_field wanted_fields,
+                            int expunge_all)
+{
+       struct maildir_expunge_context *ctx;
+        struct mail_expunge_context *mctx;
+
+       mctx = index_storage_expunge_init(box, wanted_fields, expunge_all);
+       if (mctx == NULL)
+               return NULL;
+
+       ctx = i_new(struct maildir_expunge_context, 1);
+       ctx->ctx = mctx;
+       return (struct mail_expunge_context *) ctx;
+}
+
+int maildir_storage_expunge_deinit(struct mail_expunge_context *_ctx)
+{
+       struct maildir_expunge_context *ctx =
+               (struct maildir_expunge_context *) _ctx;
+       struct mail_expunge_context *mctx;
+
+       mctx = ctx->ctx;
+       i_free(ctx);
+       return index_storage_expunge_deinit(mctx);
+}
+
+struct mail *
+maildir_storage_expunge_fetch_next(struct mail_expunge_context *_ctx)
+{
+       struct maildir_expunge_context *ctx =
+               (struct maildir_expunge_context *) _ctx;
+
+       return index_storage_expunge_fetch_next(ctx->ctx);
+}
+
+int maildir_storage_expunge(struct mail *mail,
+                           struct mail_expunge_context *_ctx,
+                           unsigned int *seq_r, int notify)
 {
-       struct mail_index_record *rec, *first_rec, *last_rec;
-       unsigned int seq, first_seq, last_seq;
-       int ret, no_permission = FALSE;
-
-       if (!index_expunge_seek_first(ibox, &seq, &rec))
-               return FALSE;
-
-       first_rec = last_rec = NULL;
-       first_seq = last_seq = 0;
-       while (rec != NULL) {
-               if ((rec->msg_flags & MAIL_DELETED) == 0)
-                       ret = FALSE;
-               else {
-                       t_push();
-                       ret = maildir_expunge_mail(ibox->index, rec);
-                       t_pop();
-
-                       if (!ret) {
-                               if (errno != EACCES)
-                                       return FALSE;
-                               no_permission = TRUE;
-                       } else {
-                               if (first_rec == NULL) {
-                                       first_rec = rec;
-                                       first_seq = seq;
-                               }
-                               last_rec = rec;
-                               last_seq = seq;
-                       }
-               }
-
-               if (!ret && first_rec != NULL) {
-                       if (!index_expunge_mails(ibox, first_rec, last_rec,
-                                                first_seq, last_seq, notify))
-                               return FALSE;
-                       first_rec = NULL;
-
-                       seq = first_seq;
-                       rec = ibox->index->lookup(ibox->index, seq);
-               } else {
-                       seq++;
-                       rec = ibox->index->next(ibox->index, rec);
-               }
+       struct maildir_expunge_context *ctx =
+               (struct maildir_expunge_context *) _ctx;
+       struct index_mail *imail = (struct index_mail *) mail;
+       int ret;
+
+       if (mail->box->readonly) {
+               /* send warning */
+               return index_storage_expunge(mail, ctx->ctx, seq_r, notify);
        }
 
-       if (first_rec != NULL) {
-               if (!index_expunge_mails(ibox, first_rec, last_rec,
-                                        first_seq, last_seq, notify))
+       t_push();
+       ret = maildir_expunge_mail(imail->ibox->index, imail->data.rec);
+       t_pop();
+
+       if (!ret) {
+               if (errno != EACCES)
                        return FALSE;
-       }
 
-       if (no_permission) {
-               ibox->box.storage->callbacks->notify_no(&ibox->box,
+               if (ctx->sent_access_warning)
+                       return TRUE;
+                ctx->sent_access_warning = TRUE;
+
+               mail->box->storage->callbacks->notify_no(mail->box,
                        "We didn't have permission to expunge all the mails",
-                       ibox->box.storage->callback_context);
+                       mail->box->storage->callback_context);
+               return TRUE;
        }
 
-       return TRUE;
+       return index_storage_expunge(mail, ctx->ctx, seq_r, notify);
 }
index f075842935c34a1800d768b2883643e9f9e1be21..054b654c885a7d9cac336b972b3e4abe86c1f0e7 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
 #include "home-expand.h"
@@ -322,6 +322,7 @@ static int verify_inbox(struct mail_storage *storage)
 static void maildir_mail_init(struct index_mail *mail)
 {
        mail->mail.copy = maildir_storage_copy;
+       mail->mail.expunge = maildir_storage_expunge;
 }
 
 static struct mailbox *
@@ -344,10 +345,8 @@ maildir_open(struct mail_storage *storage, const char *name,
 
        ibox = index_storage_mailbox_init(storage, &maildir_mailbox,
                                          index, name, flags);
-       if (ibox != NULL) {
-               ibox->expunge_locked = maildir_expunge_locked;
+       if (ibox != NULL)
                ibox->mail_init = maildir_mail_init;
-       }
        return (struct mailbox *) ibox;
 }
 
@@ -770,7 +769,6 @@ struct mailbox maildir_mailbox = {
        index_storage_get_status,
        index_storage_sync,
        maildir_storage_auto_sync,
-       index_storage_expunge,
        index_storage_fetch_init,
        index_storage_fetch_deinit,
        index_storage_fetch_next,
@@ -785,6 +783,9 @@ struct mailbox maildir_mailbox = {
        maildir_storage_save_next,
        maildir_storage_copy_init,
        maildir_storage_copy_deinit,
+       maildir_storage_expunge_init,
+       maildir_storage_expunge_deinit,
+       maildir_storage_expunge_fetch_next,
        mail_storage_is_inconsistency_error,
 
        FALSE,
index 04beaebe0e8207157fa3df9bd0a9dd57fa4b8475..9129333208becf682a34272de6af3c0dd6f1c876 100644 (file)
@@ -23,7 +23,15 @@ int maildir_list_mailbox_deinit(struct mailbox_list_context *ctx);
 struct mailbox_list *
 maildir_list_mailbox_next(struct mailbox_list_context *ctx);
 
-int maildir_expunge_locked(struct index_mailbox *ibox, int notify);
+struct mail_expunge_context *
+maildir_storage_expunge_init(struct mailbox *box,
+                            enum mail_fetch_field wanted_fields,
+                            int expunge_all);
+int maildir_storage_expunge_deinit(struct mail_expunge_context *ctx);
+struct mail *
+maildir_storage_expunge_fetch_next(struct mail_expunge_context *ctx);
+int maildir_storage_expunge(struct mail *mail, struct mail_expunge_context *ctx,
+                           unsigned int *seq_r, int notify);
 
 const char *maildir_get_path(struct mail_storage *storage, const char *name);
 
index 5820d0298e26a2b43f15062bfde36342696cc6ec..2013e9e4762906905a73a7d05d31cbb03d5c3b6e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
 #include "istream.h"
 #include "mbox-index.h"
 #include "mbox-storage.h"
 #include "mbox-lock.h"
+#include "index-expunge.h"
 
 #include <fcntl.h>
 #include <unistd.h>
 
-static int expunge_real(struct index_mailbox *ibox,
-                       struct mail_index_record *rec, unsigned int seq,
-                       struct istream *input, struct ostream *output,
-                       int notify)
-{
-       struct mail_index_record *first_rec, *last_rec;
-       uoff_t offset, hdr_size, body_size;
-       uoff_t end_offset, from_offset, copy_size, old_limit;
-       const unsigned char *data;
-       size_t size;
-       unsigned int first_seq, last_seq;
-       int expunges, skip_next, deleted, failed;
+struct mbox_expunge_context {
+       struct mail_expunge_context *ctx;
 
-       if (seq == 1)
-               end_offset = 0;
-       else {
-               /* we need to find offset to beginning of From-line.
-                  not the fastest way maybe, but easiest.. */
-               rec = ibox->index->lookup(ibox->index, seq-1);
-               
-               if (!mbox_mail_get_location(ibox->index, rec, &offset,
-                                           &hdr_size, &body_size))
-                       return FALSE;
-               end_offset = offset + hdr_size + body_size;
+        struct index_mailbox *ibox;
+       struct istream *input;
+       struct ostream *output;
+       int failed, expunges;
 
-               /* get back to the deleted record */
-               rec = ibox->index->next(ibox->index, rec);
-       }
+       uoff_t from_offset, move_offset;
+};
 
-       old_limit = input->v_limit;
+struct mail_expunge_context *
+mbox_storage_expunge_init(struct mailbox *box,
+                         enum mail_fetch_field wanted_fields, int expunge_all)
+{
+       struct index_mailbox *ibox = (struct index_mailbox *) box;
+       struct mbox_expunge_context *ctx;
+       struct mail_expunge_context *mctx;
+       struct istream *input;
 
-       first_rec = last_rec = NULL;
-       first_seq = last_seq = 0;
+       mctx = index_storage_expunge_init(box, wanted_fields, expunge_all);
+       if (mctx == NULL)
+               return NULL;
 
-       expunges = FALSE; skip_next = FALSE;
-       while (rec != NULL) {
-               if (!mbox_mail_get_location(ibox->index, rec, &offset,
-                                           &hdr_size, &body_size))
-                       return FALSE;
+       /* mbox must be already opened, synced and locked at this point.
+          we just want the istream. */
+       input = mbox_get_stream(ibox->index, 0, MAIL_LOCK_EXCLUSIVE);
+       if (input == NULL)
+               return NULL;
 
-               from_offset = end_offset;
-               end_offset = offset + hdr_size + body_size;
+       i_assert(ibox->index->mbox_sync_counter ==
+                ibox->index->mbox_lock_counter);
 
-               deleted = (rec->msg_flags & MAIL_DELETED) != 0;
-               if (deleted) {
-                       if (first_rec == NULL) {
-                               first_rec = rec;
-                               first_seq = seq;
-                       }
-                       last_rec = rec;
-                       last_seq = seq;
-
-                       if (!expunges) {
-                               /* first expunged record, seek to position
-                                  where we want to begin writing */
-                               if (o_stream_seek(output, from_offset) < 0)
-                                       return FALSE;
-                               expunges = TRUE;
-                       }
-               } else if (first_rec != NULL) {
-                       if (!index_expunge_mails(ibox, first_rec, last_rec,
-                                                first_seq, last_seq, notify))
-                               return FALSE;
-                       first_rec = NULL;
-
-                       rec = ibox->index->lookup(ibox->index, first_seq);
-                       seq = first_seq;
-                       skip_next = TRUE;
-               }
+       ctx = i_new(struct mbox_expunge_context, 1);
+       ctx->ctx = mctx;
+       ctx->ibox = ibox;
+       ctx->input = input;
+       ctx->output = o_stream_create_file(ibox->index->mbox_fd, default_pool,
+                                          4096, FALSE);
+       ctx->from_offset = (uoff_t)-1;
+       ctx->move_offset = (uoff_t)-1;
+       o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
+       return (struct mail_expunge_context *) ctx;
+}
 
-               if (skip_next)
-                       skip_next = FALSE;
-               else {
-                       rec = ibox->index->next(ibox->index, rec);
-                       seq++;
-               }
+static int mbox_move_data(struct mbox_expunge_context *ctx)
+{
+       const unsigned char *data;
+       size_t size;
+       uoff_t old_limit;
+       int failed;
 
-               if (expunges && !deleted) {
-                       /* seek to wanted input position, and copy
-                          this messages */
-                       i_assert(input->v_offset <= from_offset);
-                       i_stream_skip(input, from_offset - input->v_offset);
-
-                       if (output->offset == 0) {
-                               /* we're writing to beginning of mbox, so we
-                                  don't want the [\r]\n there */
-                               (void)i_stream_read_data(input, &data,
-                                                        &size, 1);
-                               if (size > 0 && data[0] == '\n')
-                                       i_stream_skip(input, 1);
-                               else if (size > 1 && data[0] == '\r' &&
-                                        data[1] == '\n')
-                                       i_stream_skip(input, 2);
-                       }
+       i_assert(ctx->input->v_offset <= ctx->move_offset);
+       i_stream_skip(ctx->input, ctx->move_offset - ctx->input->v_offset);
+
+       if (ctx->output->offset == 0) {
+               /* we're writing to beginning of mbox, so we
+                  don't want the [\r]\n there */
+               (void)i_stream_read_data(ctx->input, &data, &size, 1);
+               if (size > 0 && data[0] == '\n')
+                       i_stream_skip(ctx->input, 1);
+               else if (size > 1 && data[0] == '\r' &&
+                        data[1] == '\n')
+                       i_stream_skip(ctx->input, 2);
+       }
+
+       old_limit = ctx->input->v_limit;
+       i_stream_set_read_limit(ctx->input, ctx->from_offset);
+       failed = o_stream_send_istream(ctx->output, ctx->input) < 0;
+       i_stream_set_read_limit(ctx->input, old_limit);
 
-                       i_stream_set_read_limit(input, end_offset);
-                       failed = o_stream_send_istream(output, input) < 0;
-                       i_stream_set_read_limit(input, old_limit);
+       if (failed || ctx->input->v_offset != ctx->from_offset)
+               return FALSE;
+       return TRUE;
+}
 
-                       if (failed || input->v_offset != end_offset)
-                               return FALSE;
+int mbox_storage_expunge_deinit(struct mail_expunge_context *_ctx)
+{
+       struct mbox_expunge_context *ctx = (struct mbox_expunge_context *) _ctx;
+       int failed = ctx->failed;
+
+       if (ctx->expunges) {
+               if (!failed && ctx->move_offset != (uoff_t)-1) {
+                       ctx->from_offset = ctx->input->v_limit;
+                       if (!mbox_move_data(ctx))
+                               failed = TRUE;
+               } else if (failed && ctx->output->offset > 0) {
+                       /* we moved some of the data. move the rest as well
+                          so there won't be invalid holes in mbox file */
+                       (void)o_stream_send_istream(ctx->output, ctx->input);
                }
-       }
 
-       if (first_rec != NULL) {
-               if (!index_expunge_mails(ibox, first_rec, last_rec,
-                                        first_seq, last_seq, notify))
-                       return FALSE;
+               if (ftruncate(ctx->ibox->index->mbox_fd,
+                             (off_t)ctx->output->offset) < 0) {
+                       mail_storage_set_error(ctx->ibox->box.storage,
+                               "ftruncate() failed for mbox file %s: %m",
+                               ctx->ibox->index->mailbox_path);
+                       failed = TRUE;
+               }
        }
 
-       i_stream_skip(input, end_offset - input->v_offset);
-
-       /* copy the rest as well, should be only \n but someone might
-          as well just appended more data.. but if we've deleted all mail,
-          don't write the only \n there. */
-       copy_size = input->v_size - input->v_offset;
-       if (output->offset == 0 && copy_size == 1)
-               return TRUE;
+       if (!index_storage_expunge_deinit(ctx->ctx))
+               failed = TRUE;
 
-       return o_stream_send_istream(output, input) >= 0;
+       o_stream_unref(ctx->output);
+       i_free(ctx);
+       return !failed;
 }
 
-int mbox_expunge_locked(struct index_mailbox *ibox, int notify)
+static int get_from_offset(struct mail_index *index,
+                          struct mail_index_record *rec, uoff_t *offset_r)
 {
-       struct mail_index_record *rec;
-       struct istream *input;
-       struct ostream *output;
-       unsigned int seq;
-       int failed;
+       uoff_t offset, hdr_size, body_size;
 
-       if (!index_expunge_seek_first(ibox, &seq, &rec))
+       if (!mbox_mail_get_location(index, rec, &offset,
+                                   &hdr_size, &body_size))
                return FALSE;
 
-       if (rec == NULL) {
-               /* no deleted messages */
-               return TRUE;
+       *offset_r = offset + hdr_size + body_size;
+       return TRUE;
+}
+
+struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *_ctx)
+{
+       struct mbox_expunge_context *ctx =
+               (struct mbox_expunge_context *) _ctx;
+       struct mail_expunge_context *mctx = ctx->ctx;
+       struct mail_index *index = ctx->ibox->index;
+
+       if (mctx->rec == NULL)
+               return NULL;
+
+       if (mctx->fetch_next) {
+                mctx->fetch_next = FALSE;
+               do {
+                       if (!get_from_offset(index, mctx->rec,
+                                            &ctx->from_offset)) {
+                               ctx->failed = TRUE;
+                               return NULL;
+                       }
+
+                       mctx->seq++;
+                       mctx->rec = index->next(index, mctx->rec);
+                       if (mctx->rec == NULL)
+                               return NULL;
+               } while ((mctx->rec->msg_flags & MAIL_DELETED) == 0 &&
+                        !mctx->expunge_all);
        }
 
-       /* mbox must be already opened, synced and locked at this point.
-          we just want the istream. */
-       input = mbox_get_stream(ibox->index, 0, MAIL_LOCK_EXCLUSIVE);
-       if (input == NULL)
-               return FALSE;
+       return index_storage_expunge_fetch_next(ctx->ctx);
+}
 
-       i_assert(ibox->index->mbox_sync_counter ==
-                ibox->index->mbox_lock_counter);
+static int get_prev_from_offset(struct mbox_expunge_context *ctx,
+                               unsigned int seq)
+{
+       struct mail_index_record *rec;
+
+       if (seq == 1)
+               ctx->from_offset = 0;
+       else {
+               rec = ctx->ibox->index->lookup(ctx->ibox->index, seq-1);
+
+               if (!get_from_offset(ctx->ibox->index, rec, &ctx->from_offset))
+                       return FALSE;
+       }
 
-       t_push();
-       output = o_stream_create_file(ibox->index->mbox_fd, data_stack_pool,
-                                     4096, FALSE);
-       o_stream_set_blocking(output, 60000, NULL, NULL);
+       return TRUE;
+}
 
-       failed = !expunge_real(ibox, rec, seq, input, output, notify);
+int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *_ctx,
+                        unsigned int *seq_r, int notify)
+{
+       struct mbox_expunge_context *ctx = (struct mbox_expunge_context *) _ctx;
+       struct index_mail *imail = (struct index_mail *) mail;
 
-       if (failed && output->offset > 0) {
-               /* we moved some of the data. move the rest as well so there
-                  won't be invalid holes in mbox file */
-               (void)o_stream_send_istream(output, input);
+       if (ctx->from_offset == (uoff_t)-1) {
+               if (!get_prev_from_offset(ctx, imail->data.idx_seq))
+                       return FALSE;
        }
 
-       if (ftruncate(ibox->index->mbox_fd, (off_t)output->offset) < 0) {
-               mail_storage_set_error(ibox->box.storage, "ftruncate() failed "
-                                      "for mbox file %s: %m",
-                                      ibox->index->mailbox_path);
-               failed = TRUE;
+       if (!ctx->expunges) {
+               /* first expunged message */
+               if (o_stream_seek(ctx->output, ctx->from_offset) < 0)
+                       return FALSE;
+               ctx->expunges = TRUE;
+       } else if (ctx->move_offset != ctx->from_offset) {
+               if (!mbox_move_data(ctx))
+                       return FALSE;
        }
 
-       o_stream_unref(output);
-       t_pop();
+       if (!get_from_offset(ctx->ibox->index, imail->data.rec,
+                            &ctx->move_offset))
+               return FALSE;
 
-       return !failed;
+       return index_storage_expunge(mail, ctx->ctx, seq_r, notify);
 }
index fca4f2e7e4f858d8f2dcb793cefa4e76b1f6c9d9..c540857ae6ae0a559b1ef15bbbb5464a44165a8a 100644 (file)
@@ -319,6 +319,11 @@ static const char *mbox_get_path(struct mail_storage *storage, const char *name)
        return t_strconcat(storage->dir, "/", name, NULL);
 }
 
+static void mbox_mail_init(struct index_mail *mail)
+{
+       mail->mail.expunge = mbox_storage_expunge;
+}
+
 static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
                                 enum mailbox_open_flags flags)
 {
@@ -349,7 +354,7 @@ static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
        ibox = index_storage_mailbox_init(storage, &mbox_mailbox, index,
                                          name, flags);
        if (ibox != NULL)
-               ibox->expunge_locked = mbox_expunge_locked;
+               ibox->mail_init = mbox_mail_init;
        return (struct mailbox *) ibox;
 }
 
@@ -780,7 +785,6 @@ struct mailbox mbox_mailbox = {
        index_storage_get_status,
        index_storage_sync,
        mbox_storage_auto_sync,
-       index_storage_expunge,
        index_storage_fetch_init,
        index_storage_fetch_deinit,
        index_storage_fetch_next,
@@ -795,6 +799,9 @@ struct mailbox mbox_mailbox = {
        mbox_storage_save_next,
        index_storage_copy_init,
        index_storage_copy_deinit,
+       mbox_storage_expunge_init,
+       mbox_storage_expunge_deinit,
+       mbox_storage_expunge_fetch_next,
        mail_storage_is_inconsistency_error,
 
        FALSE,
index 427c6282fad47be301651e176f49c099380d18b1..7580dbeaf1cdb68d59fcbd642f8275089f6dae49 100644 (file)
@@ -20,7 +20,13 @@ mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
 int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx);
 struct mailbox_list *mbox_list_mailbox_next(struct mailbox_list_context *ctx);
 
-int mbox_expunge_locked(struct index_mailbox *ibox, int notify);
+struct mail_expunge_context *
+mbox_storage_expunge_init(struct mailbox *box,
+                         enum mail_fetch_field wanted_fields, int expunge_all);
+int mbox_storage_expunge_deinit(struct mail_expunge_context *ctx);
+struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *ctx);
+int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *ctx,
+                        unsigned int *seq_r, int notify);
 
 int mbox_is_valid_mask(const char *mask);
 
index 91e70b22f16dda9fd0fd0c23dcc07627addc6e38..9d442f87d8235b95dbfa6e632766a403a44af0d8 100644 (file)
@@ -235,10 +235,10 @@ struct mailbox {
 
        /* Explicitly lock the mailbox. If not used, all the methods below
           use the minimum locking requirements. This allows you to for
-          example use the expunge() and update_flags() methods in
-          struct mail. The mailbox stays locked until you unlock it.
-          Note that if you call a method which wants more locks than you've
-          given here, the call will fail (to avoid deadlocks). */
+          example use the update_flags() method in struct mail. The mailbox
+          stays locked until you unlock it. Note that if you call a method
+          which wants more locks than you've given here, the call will fail
+          (to avoid deadlocks). */
        int (*lock)(struct mailbox *box, enum mailbox_lock_type lock_type);
 
        /* Gets the mailbox status information. */
@@ -253,10 +253,6 @@ struct mailbox {
        void (*auto_sync)(struct mailbox *box, enum mailbox_sync_type sync_type,
                          unsigned int min_newmail_notify_interval);
 
-       /* Expunge all mails with \Deleted flag. If notify is TRUE, call
-          expunge callbacks. Also always does full syncing. */
-       int (*expunge)(struct mailbox *box, int notify);
-
        /* Initialize new fetch request. wanted_fields isn't required, but it
           can be used for optimizations. update_flags must be set to TRUE, if
           you want to call mail->update_flags() */
@@ -324,11 +320,22 @@ struct mailbox {
 
        /* Initialize copying operation to this mailbox. The actual copying
           can be done by fetching or searching mails and calling mail's
-          expunge() method. */
+          copy() method. */
        struct mail_copy_context *(*copy_init)(struct mailbox *box);
        /* Finish copying. */
        int (*copy_deinit)(struct mail_copy_context *ctx, int rollback);
 
+       /* Initialize expunging operation to this mailbox. If expunge_all
+          is TRUE, all messages are returned rather than just deleted. */
+       struct mail_expunge_context *
+               (*expunge_init)(struct mailbox *box,
+                               enum mail_fetch_field wanted_fields,
+                               int expunge_all);
+       /* Finish expunging. */
+       int (*expunge_deinit)(struct mail_expunge_context *ctx);
+       /* Fetch next mail. */
+       struct mail *(*expunge_fetch_next)(struct mail_expunge_context *ctx);
+
        /* Returns TRUE if mailbox is now in inconsistent state, meaning that
           the message IDs etc. may have changed - only way to recover this
           would be to fully close the mailbox and reopen it. With IMAP
@@ -393,6 +400,21 @@ struct mail {
 
        /* Copy this message to another mailbox. */
        int (*copy)(struct mail *mail, struct mail_copy_context *ctx);
+
+       /* Expunge this message. Note that the actual message may or may not
+          be really expunged until expunge_deinit() is called. In any case,
+          after this call you must not try to access this mail, or any other
+          mail you've previously fetched.
+
+          Since you can't be sure when the message is really expunged, you
+          can't be sure what it's sequence number is from client's point of
+          view. seq_r is set to that sequence number.
+
+          This call is allowed only for mails fetched with
+          expunge_fetch_next(). Otherwise the sequence number updates would
+          get too tricky. */
+       int (*expunge)(struct mail *mail, struct mail_expunge_context *ctx,
+                      unsigned int *seq_r, int notify);
 };
 
 struct mailbox_list {
index 91968d3434b4e75ce3947b7a566cb76d0d2f4774..b30bf94b3f91a0e53d8d9af543ac14e9ed28711f 100644 (file)
@@ -63,7 +63,7 @@ static int init_mailbox(struct client *client)
        for (i = 0; i < 2; i++) {
                ctx = client->mailbox->fetch_init(client->mailbox,
                                                  MAIL_FETCH_SIZE,
-                                                 NULL, messageset, FALSE);
+                                                 messageset, FALSE);
                if (ctx == NULL) {
                        client_send_storage_error(client);
                        return FALSE;
index 1cfe0596ff2df250daaad47ffb4d749b275fd2ab..05e4c4b9dec531201ca781549216ba37e8a13705 100644 (file)
@@ -139,63 +139,44 @@ static int cmd_noop(struct client *client, const char *args __attr_unused__)
        return TRUE;
 }
 
-static int cmd_quit(struct client *client, const char *args __attr_unused__)
+static int expunge_mails(struct client *client, struct mailbox *box)
 {
-       unsigned int first, last, msgnum, max, i, j;
-       struct mail_full_flags flags;
-       string_t *set;
-
-       if (!client->deleted) {
-               client_send_line(client, "+OK Logging out.");
-               client_disconnect(client);
-               return TRUE;
-       }
-
-       set = t_str_new(1024);
-       first = last = 0; msgnum = 1;
-       max = MSGS_BITMASK_SIZE(client);
-       for (i = 0; i < max; i++) {
-               if (client->deleted_bitmask[i] == 0) {
-                        msgnum += CHAR_BIT;
-                       continue;
-               }
+       struct mail_expunge_context *ctx;
+       struct mail *mail;
+       unsigned int i, j;
+       int failed = FALSE;
+
+       /* NOTE: if there's any external expunges, they'll get synced here.
+          Currently we update only the deleted_bitmask[] so we don't end up
+          expunging wrong messages, but message_sizes[] isn't updated. */
+       ctx = box->expunge_init(box, 0, TRUE);
+       if (ctx == NULL)
+               return FALSE;
 
-               for (j = 0; j < CHAR_BIT; j++, msgnum++) {
-                       if ((client->deleted_bitmask[i] & (1 << j)) == 0)
-                               continue;
-
-                       if (last == msgnum-1 && last != 0)
-                               last++;
-                       else {
-                               if (first != 0) {
-                                       if (first == last)
-                                               str_printfa(set, ",%u", first);
-                                       else {
-                                               str_printfa(set, ",%u:%u",
-                                                           first, last);
-                                       }
-                               }
-                               first = last = msgnum;
+       i = j = 0;
+       while ((mail = box->expunge_fetch_next(ctx)) != NULL) {
+               if ((client->deleted_bitmask[i] & (1 << j)) != 0) {
+                       if (!mail->expunge(mail, ctx, NULL, FALSE)) {
+                               failed = TRUE;
+                               break;
                        }
                }
+               if (++j == CHAR_BIT) {
+                       j = 0; i++;
+               }
        }
 
-       if (first != 0) {
-               if (first == last)
-                       str_printfa(set, ",%u", first);
-               else
-                       str_printfa(set, ",%u:%u", first, last);
-       }
+       if (!box->expunge_deinit(ctx))
+               return FALSE;
 
-       memset(&flags, 0, sizeof(flags));
-       flags.flags = MAIL_DELETED;
+       return !failed;
+}
 
-       if (str_len(set) == 0)
+static int cmd_quit(struct client *client, const char *args __attr_unused__)
+{
+       if (!client->deleted)
                client_send_line(client, "+OK Logging out.");
-       else if (client->mailbox->update_flags(client->mailbox, str_c(set)+1,
-                                              FALSE, &flags, MODIFY_ADD,
-                                              FALSE, NULL) &&
-                client->mailbox->expunge(client->mailbox, FALSE))
+       else if (expunge_mails(client, client->mailbox))
                client_send_line(client, "+OK Logging out, messages deleted.");
        else
                client_send_storage_error(client);
@@ -281,8 +262,7 @@ static void fetch(struct client *client, unsigned int msgnum,
        ctx = client->mailbox->fetch_init(client->mailbox,
                                          MAIL_FETCH_STREAM_HEADER |
                                          MAIL_FETCH_STREAM_BODY,
-                                         NULL, dec2str(msgnum+1),
-                                         FALSE);
+                                         dec2str(msgnum+1), FALSE);
        if (ctx == NULL) {
                client_send_storage_error(client);
                return;
@@ -366,7 +346,7 @@ static void list_uids(struct client *client, unsigned int message)
                t_strdup_printf("%u", message);
 
        ctx = client->mailbox->fetch_init(client->mailbox, 0,
-                                         NULL, messageset, FALSE);
+                                         messageset, FALSE);
        if (ctx == NULL) {
                client_send_storage_error(client);
                return;
index 1a2b164521a8ac5af4877ee2581245766ff84d25..6f8b0f1a6f0e07395139684198f727dd9091b191 100644 (file)
@@ -22,17 +22,40 @@ static void notify_no(struct mailbox *mailbox __attr_unused__,
 }
 
 static void expunge(struct mailbox *mailbox __attr_unused__,
-                   unsigned int seq __attr_unused__,
-                   void *context __attr_unused__)
+                   unsigned int seq, void *context)
 {
+       struct client *client = context;
+       unsigned char *mask = client->deleted_bitmask;
+       unsigned int max, i, j;
+
+       /* external deletes - we have to fix our internal deleted array.
+          this should happen only when we're doing the expunging at quit. */
+       seq--;
+       client->messages_count--;
+
+       if (!client->deleted)
+               return;
+
+       max = client->messages_count / CHAR_BIT;
+       i = seq / CHAR_BIT; j = seq % CHAR_BIT;
+       mask[i] = (mask[i] & ((1 << j) - 1)) |
+               ((mask[i] >> (j+1)) << j) |
+               (i == max ? 0 : ((mask[i+1] & 1) << (CHAR_BIT-1)));
+
+       if (i != max) {
+               for (i++; i < max-1; i++) {
+                       mask[i] = (mask[i] >> 1) |
+                               ((mask[i+1] & 1) << (CHAR_BIT-1));
+               }
+
+               mask[i] >>= 1;
+       }
 }
 
 static void update_flags(struct mailbox *mailbox __attr_unused__,
                         unsigned int seq __attr_unused__,
                         unsigned int uid __attr_unused__,
-                        enum mail_flags flags __attr_unused__,
-                        const char *custom_flags[] __attr_unused__,
-                        unsigned int custom_flags_count __attr_unused__,
+                        const struct mail_full_flags *flags __attr_unused__,
                         void *context __attr_unused__)
 {
 }