]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
mbox code compiles again, but syncing is only partially implemented so
authorTimo Sirainen <tss@iki.fi>
Thu, 6 May 2004 01:22:25 +0000 (04:22 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 6 May 2004 01:22:25 +0000 (04:22 +0300)
accessing mboxes fails..

Also some cleanups to index-storage and maildir code.

--HG--
branch : HEAD

32 files changed:
configure.in
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/maildir/maildir-list.c
src/lib-storage/index/maildir/maildir-mail.c
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/maildir/maildir-storage.h
src/lib-storage/index/maildir/maildir-sync.c
src/lib-storage/index/maildir/maildir-uidlist.c
src/lib-storage/index/maildir/maildir-uidlist.h
src/lib-storage/index/mbox/Makefile.am
src/lib-storage/index/mbox/istream-raw-mbox.c
src/lib-storage/index/mbox/istream-raw-mbox.h
src/lib-storage/index/mbox/mbox-expunge.c [deleted file]
src/lib-storage/index/mbox/mbox-file.c [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-file.h [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-from.c
src/lib-storage/index/mbox/mbox-from.h
src/lib-storage/index/mbox/mbox-list.c
src/lib-storage/index/mbox/mbox-lock.c [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-lock.h [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-mail.c [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-save.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/mbox/mbox-storage.h
src/lib-storage/index/mbox/mbox-sync-parse.c
src/lib-storage/index/mbox/mbox-sync-private.h
src/lib-storage/index/mbox/mbox-sync-rewrite.c
src/lib-storage/index/mbox/mbox-sync.c
src/lib-storage/index/mbox/mbox-transaction.c [new file with mode: 0644]

index 54c10acf52209697241db2d18c2b5489ff6e640e..cc2c0b4cb5ce233e0c379f27e9173f21cd98b224 100644 (file)
@@ -1,7 +1,7 @@
 AC_INIT(src)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(dovecot, 1.0-test3)
+AM_INIT_AUTOMAKE(dovecot, 1.0-test6)
 
 AM_MAINTAINER_MODE
 
@@ -195,7 +195,7 @@ AM_CONDITIONAL(BUILD_POP3D, test "$want_pop3d" = "yes")
 AC_ARG_WITH(storages,
 [  --with-storages         Build specified mail storage formats (maildir,mbox)], [
        mail_storages=`echo "$withval"|sed 's/,/ /g'` ],
-       mail_storages="maildir")
+       mail_storages="maildir mbox")
 
 dnl * gcc specific options
 if test "x$ac_cv_prog_gcc" = "xyes"; then
index d21a81eaeb622cd200750d5d1e8691fe49bf433c..6708cb788b7bd81ea757257fe72ff1dfb8586917 100644 (file)
@@ -200,6 +200,21 @@ const struct message_part *index_mail_get_parts(struct mail *_mail)
        return data->parts;
 }
 
+time_t index_mail_get_received_date(struct mail *_mail)
+{
+       struct index_mail *mail = (struct index_mail *) _mail;
+       struct index_mail_data *data = &mail->data;
+
+       if (data->received_date == (time_t)-1 &&
+           (mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) == 0) {
+               data->received_date = index_mail_get_cached_received_date(mail);
+               if (data->received_date != (time_t)-1)
+                       return data->received_date;
+       }
+
+       return data->received_date;
+}
+
 time_t index_mail_get_date(struct mail *_mail, int *timezone)
 {
        struct index_mail *mail = (struct index_mail *) _mail;
index 384a4be6a63998c799b9c77f0d0711b4a258b3de..d5c5b4eb5b12f551b675d4621f9c9a14f8a29afb 100644 (file)
@@ -94,6 +94,7 @@ struct istream *index_mail_get_headers(struct mail *_mail,
 
 const struct mail_full_flags *index_mail_get_flags(struct mail *_mail);
 const struct message_part *index_mail_get_parts(struct mail *_mail);
+time_t index_mail_get_received_date(struct mail *_mail);
 time_t index_mail_get_date(struct mail *_mail, int *timezone);
 uoff_t index_mail_get_size(struct mail *_mail);
 struct istream *index_mail_init_stream(struct index_mail *mail,
index 66ebbe93c2b40d42664957049ac2004449d89e89..ee3e33f7b875b5b8caf0ba45afe8d002ece66550 100644 (file)
@@ -39,8 +39,11 @@ void index_storage_init(struct index_storage *storage __attr_unused__)
        index_storage_refcount++;
 }
 
-void index_storage_deinit(struct index_storage *storage __attr_unused__)
+void index_storage_deinit(struct index_storage *storage)
 {
+       i_free(storage->storage.namespace);
+       i_free(storage->storage.error);
+
        if (--index_storage_refcount > 0)
                return;
 
@@ -243,10 +246,10 @@ static enum mail_cache_field get_never_cache_fields(void)
        return ret;
 }
 
-static void lock_notify(enum mailbox_lock_notify_type notify_type,
-                       unsigned int secs_left, void *context)
+void index_storage_lock_notify(struct index_mailbox *ibox,
+                              enum mailbox_lock_notify_type notify_type,
+                              unsigned int secs_left)
 {
-       struct index_mailbox *ibox = context;
        struct index_storage *storage = ibox->storage;
        const char *str;
        time_t now;
@@ -293,7 +296,7 @@ static void lock_notify(enum mailbox_lock_notify_type notify_type,
        }
 }
 
-void index_storage_reset_lock_notify(struct index_mailbox *ibox)
+void index_storage_lock_notify_reset(struct index_mailbox *ibox)
 {
        ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
        ibox->last_notify_type = MAILBOX_LOCK_NOTIFY_NONE;
index cf0378c090263151fb6a99d8b68155bac807f0be..52c45774dbf99541453ea2615dce4458ae1d3c51 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __INDEX_STORAGE_H
 #define __INDEX_STORAGE_H
 
+#include "file-dotlock.h"
 #include "mail-storage-private.h"
 #include "mail-index.h"
 #include "index-mail.h"
@@ -74,7 +75,21 @@ struct index_mailbox {
        uint32_t commit_log_file_seq;
        uoff_t commit_log_file_offset;
 
-       /* sync: */
+       /* mbox: */
+       int mbox_fd;
+       struct istream *mbox_stream, *mbox_file_stream;
+       int mbox_lock_type;
+       dev_t mbox_dev;
+       ino_t mbox_ino;
+       unsigned int mbox_locks;
+       struct dotlock mbox_dotlock;
+       unsigned int mbox_lock_id;
+
+       buffer_t *mbox_data_buf;
+       const uoff_t *mbox_data;
+       uint32_t mbox_data_count;
+
+       /* maildir sync: */
        struct maildir_uidlist *uidlist;
        time_t last_new_mtime, last_cur_mtime, last_new_sync_time;
        time_t dirty_cur_time;
@@ -99,7 +114,11 @@ struct index_transaction_context {
 };
 
 int mail_storage_set_index_error(struct index_mailbox *ibox);
-void index_storage_reset_lock_notify(struct index_mailbox *ibox);
+
+void index_storage_lock_notify(struct index_mailbox *ibox,
+                              enum mailbox_lock_notify_type notify_type,
+                              unsigned int secs_left);
+void index_storage_lock_notify_reset(struct index_mailbox *ibox);
 
 struct mail_index *
 index_storage_alloc(const char *index_dir,
index 1558473de6317a85e9faf1cbfb6dd0f0f83ffbec..0c2ab5978b3ceadfc4afdc04dbfcfa7c5a07ef56 100644 (file)
@@ -19,7 +19,6 @@ struct maildir_list_context {
        struct mailbox_list_context mailbox_ctx;
        pool_t pool;
 
-       struct mail_storage *storage;
        const char *dir, *prefix;
         enum mailbox_list_flags flags;
 
@@ -63,7 +62,7 @@ static int maildir_fill_readdir(struct maildir_list_context *ctx,
        dirp = opendir(ctx->dir);
        if (dirp == NULL) {
                if (errno != ENOENT) {
-                       mail_storage_set_critical(ctx->storage,
+                       mail_storage_set_critical(ctx->mailbox_ctx.storage,
                                "opendir(%s) failed: %m", ctx->dir);
                        return FALSE;
                }
@@ -171,7 +170,7 @@ static int maildir_fill_readdir(struct maildir_list_context *ctx,
        }
 
        if (closedir(dirp) < 0) {
-               mail_storage_set_critical(ctx->storage,
+               mail_storage_set_critical(ctx->mailbox_ctx.storage,
                                          "readdir(%s) failed: %m", ctx->dir);
                return FALSE;
        }
@@ -184,7 +183,8 @@ static int maildir_fill_readdir(struct maildir_list_context *ctx,
 static int maildir_fill_subscribed(struct maildir_list_context *ctx,
                                   struct imap_match_glob *glob)
 {
-       struct index_storage *istorage = (struct index_storage *)ctx->storage;
+       struct index_storage *istorage =
+               (struct index_storage *)ctx->mailbox_ctx.storage;
        struct subsfile_list_context *subsfile_ctx;
        const char *path, *name, *p;
        struct mailbox_node *node;
@@ -193,7 +193,7 @@ static int maildir_fill_subscribed(struct maildir_list_context *ctx,
        path = t_strconcat(istorage->control_dir != NULL ?
                           istorage->control_dir : istorage->dir,
                           "/" SUBSCRIPTION_FILE_NAME, NULL);
-       subsfile_ctx = subsfile_list_init(ctx->storage, path);
+       subsfile_ctx = subsfile_list_init(ctx->mailbox_ctx.storage, path);
        if (subsfile_ctx == NULL)
                return FALSE;
 
@@ -245,8 +245,8 @@ maildir_mailbox_list_init(struct mail_storage *storage,
 
        pool = pool_alloconly_create("maildir_list", 1024);
        ctx = p_new(pool, struct maildir_list_context, 1);
+       ctx->mailbox_ctx.storage = storage;
        ctx->pool = pool;
-       ctx->storage = storage;
        ctx->flags = flags;
        ctx->tree_ctx = mailbox_tree_init(MAILDIR_FS_SEP);
 
@@ -352,7 +352,7 @@ maildir_mailbox_list_next(struct mailbox_list_context *_ctx)
 
                str_truncate(ctx->node_path, 0);
                node = find_next(&ctx->root, ctx->node_path,
-                                ctx->storage->hierarchy_sep);
+                                ctx->mailbox_ctx.storage->hierarchy_sep);
                 ctx->parent_pos = str_len(ctx->node_path);
 
                if (node == NULL)
@@ -364,8 +364,10 @@ maildir_mailbox_list_next(struct mailbox_list_context *_ctx)
        node->flags &= ~MAILBOX_FLAG_MATCHED;
 
        str_truncate(ctx->node_path, ctx->parent_pos);
-       if (ctx->parent_pos != 0)
-               str_append_c(ctx->node_path, ctx->storage->hierarchy_sep);
+       if (ctx->parent_pos != 0) {
+               str_append_c(ctx->node_path,
+                            ctx->mailbox_ctx.storage->hierarchy_sep);
+       }
        str_append(ctx->node_path, node->name);
 
        ctx->list.name = str_c(ctx->node_path);
index ace8ca460cd5512662d2cbdfc2968fa17d90d23a..3afce7b84114cfa8cc7da41750683dd048e5c1a4 100644 (file)
@@ -68,9 +68,8 @@ static const struct mail_full_flags *maildir_mail_get_flags(struct mail *_mail)
 {
        struct index_mail *mail = (struct index_mail *)_mail;
        struct index_mail_data *data = &mail->data;
-        const struct mail_full_flags *flags;
 
-       flags = index_mail_get_flags(_mail);
+       (void)index_mail_get_flags(_mail);
 
        if (maildir_uidlist_is_recent(mail->ibox->uidlist, _mail->uid))
                data->flags.flags |= MAIL_RECENT;
@@ -84,15 +83,10 @@ static time_t maildir_mail_get_received_date(struct mail *_mail)
        struct stat st;
        int fd;
 
+       (void)index_mail_get_received_date(_mail);
        if (data->received_date != (time_t)-1)
                return data->received_date;
 
-       if ((mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) == 0) {
-               data->received_date = index_mail_get_cached_received_date(mail);
-               if (data->received_date != (time_t)-1)
-                       return data->received_date;
-       }
-
        if (data->stream != NULL) {
                fd = i_stream_get_fd(data->stream);
                i_assert(fd != -1);
index fabe7cc8628b4f2b6ddd614553924ca899402a29..da38995f59fe48955a06fba11b215ec140f3ae29 100644 (file)
@@ -108,9 +108,6 @@ static void maildir_free(struct mail_storage *_storage)
 
        index_storage_deinit(storage);
 
-       i_free(storage->storage.namespace);
-       i_free(storage->storage.error);
-
        i_free(storage->dir);
        i_free(storage->inbox_path);
        i_free(storage->index_dir);
index 3641343ff80bfbf75425c0603c10374ec5148819..6dfe436476c678acf3468d81468a4b6d5fa96394 100644 (file)
@@ -57,9 +57,6 @@ int maildir_copy(struct mailbox_transaction_context *t, struct mail *mail);
 int maildir_copy_commit(struct maildir_copy_context *ctx);
 void maildir_copy_rollback(struct maildir_copy_context *ctx);
 
-int maildir_storage_expunge(struct mail *mail,
-                           struct mailbox_transaction_context *t);
-
 const char *maildir_fix_mailbox_name(struct index_storage *storage,
                                     const char *name, int remove_namespace);
 const char *maildir_get_path(struct index_storage *storage, const char *name);
index d96678f5cf045616571417e2c56cbaddd2191f2e..c774586152fabbad13e4061ad46a5a3bbf9087f1 100644 (file)
@@ -390,6 +390,13 @@ static int maildir_scan_dir(struct maildir_sync_context *ctx, int new_dir)
                if (dp->d_name[0] == '.')
                        continue;
 
+               ret = maildir_uidlist_sync_next_pre(ctx->uidlist_sync_ctx,
+                                                   dp->d_name);
+               if (ret == 0)
+                       continue;
+               if (ret < 0)
+                       break;
+
                flags = 0;
                if (move_new) {
                        str_truncate(src, 0);
index e1d480659f80545facc317a9ace2cb1ab10cc06c..deb4ff09b849ef12702a53fad9ba85fd1da0ed9b 100644 (file)
@@ -58,6 +58,7 @@ struct maildir_uidlist_sync_ctx {
 
        unsigned int partial:1;
        unsigned int synced:1;
+       unsigned int locked:1;
        unsigned int failed:1;
 };
 
@@ -559,8 +560,10 @@ static int maildir_uidlist_sync_uidlist(struct maildir_uidlist_sync_ctx *ctx)
        /* lock and update uidlist to see if it's just been added */
        ret = maildir_uidlist_try_lock(ctx->uidlist);
        if (ret <= 0) {
-               if (ret == 0)
-                       return 1; // FIXME: does it work right?
+               if (ret == 0) {
+                       ctx->locked = TRUE;
+                       return -1;
+               }
                ctx->failed = TRUE;
                return -1;
        }
@@ -580,21 +583,10 @@ maildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
 {
        struct maildir_uidlist *uidlist = ctx->uidlist;
        struct maildir_uidlist_rec *rec;
-       int ret;
 
        /* we'll update uidlist directly */
        rec = hash_lookup(uidlist->files, filename);
-       if (rec == NULL && !ctx->synced) {
-               ret = maildir_uidlist_sync_uidlist(ctx);
-               if (ret < 0)
-                       return -1;
-               if (ret == 0) {
-                       return maildir_uidlist_sync_next_partial(ctx, filename,
-                                                                flags);
-               }
-
-               rec = hash_lookup(uidlist->files, filename);
-       }
+       i_assert(rec != NULL || ctx->synced);
 
        if (rec == NULL) {
                if (ctx->new_files_count == 0) {
@@ -616,13 +608,33 @@ maildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
        return 1;
 }
 
+int maildir_uidlist_sync_next_pre(struct maildir_uidlist_sync_ctx *ctx,
+                                 const char *filename)
+{
+       int ret;
+
+       if (!ctx->synced &&
+           hash_lookup(ctx->uidlist->files, filename) == NULL &&
+           (ctx->partial || hash_lookup(ctx->files, filename) == NULL)) {
+               if (ctx->locked)
+                       return 0;
+
+               ret = maildir_uidlist_sync_uidlist(ctx);
+               if (ret < 0)
+                       return ctx->locked ? 0 : -1;
+               if (ret == 0)
+                       return maildir_uidlist_sync_next_pre(ctx, filename);
+       }
+
+       return 1;
+}
+
 int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
                              const char *filename,
                              enum maildir_uidlist_rec_flag flags)
 {
        struct maildir_uidlist *uidlist = ctx->uidlist;
        struct maildir_uidlist_rec *rec, *old_rec;
-       int ret;
 
        if (ctx->failed)
                return -1;
@@ -642,16 +654,7 @@ int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
                                MAILDIR_UIDLIST_REC_FLAG_MOVED);
        } else {
                old_rec = hash_lookup(uidlist->files, filename);
-               if (old_rec == NULL && !ctx->synced) {
-                       ret = maildir_uidlist_sync_uidlist(ctx);
-                       if (ret < 0)
-                               return -1;
-                       if (ret == 0) {
-                               return maildir_uidlist_sync_next(ctx, filename,
-                                                                flags);
-                       }
-                       old_rec = hash_lookup(uidlist->files, filename);
-               }
+               i_assert(old_rec != NULL || ctx->synced);
 
                rec = p_new(ctx->record_pool, struct maildir_uidlist_rec, 1);
 
@@ -762,10 +765,10 @@ int maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx *ctx)
 {
        int ret = ctx->failed ? -1 : 0;
 
-       // FIXME: we most likely don't handle ctx->failed well enough
-       if (!ctx->partial)
-               maildir_uidlist_swap(ctx);
-       else {
+       if (!ctx->partial) {
+               if (!ctx->failed && !ctx->locked)
+                       maildir_uidlist_swap(ctx);
+       else {
                if (ctx->new_files_count != 0) {
                        maildir_uidlist_assign_uids(ctx->uidlist,
                                                    ctx->first_new_pos);
@@ -773,7 +776,7 @@ int maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx *ctx)
                maildir_uidlist_mark_all(ctx->uidlist, FALSE);
        }
 
-       if (ctx->new_files_count != 0 && ret == 0)
+       if (ctx->new_files_count != 0 && !ctx->failed && !ctx->locked)
                ret = maildir_uidlist_rewrite(ctx->uidlist);
 
        if (UIDLIST_IS_LOCKED(ctx->uidlist))
index e5b6f89848936faf2b005b77606b7af103fa2fd0..b7ba6b2cab04b14c2712c78473e9cbfa1ac88985 100644 (file)
@@ -31,6 +31,9 @@ uint32_t maildir_uidlist_get_recent_count(struct maildir_uidlist *uidlist);
 /* Sync uidlist with what's actually on maildir. */
 struct maildir_uidlist_sync_ctx *
 maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, int partial);
+/* Returns 1 = ok, -1 = error, 0 = new file and dovecot-uidlist is locked */
+int maildir_uidlist_sync_next_pre(struct maildir_uidlist_sync_ctx *ctx,
+                                 const char *filename);
 int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
                              const char *filename,
                              enum maildir_uidlist_rec_flag flags);
index 2d0aa00f904b44b8036723bafe8f2e4c1873d69a..ef9ac978099da78578d032823c04f144330b9776 100644 (file)
@@ -11,18 +11,23 @@ INCLUDES = \
 
 libstorage_mbox_a_SOURCES = \
        istream-raw-mbox.c \
-       mbox-expunge.c \
+       mbox-file.c \
        mbox-from.c \
        mbox-list.c \
+       mbox-lock.c \
+       mbox-mail.c \
        mbox-save.c \
        mbox-sync-parse.c \
        mbox-sync-rewrite.c \
        mbox-sync-update.c \
-       mbox-sync.c
-       mbox-storage.c
+       mbox-sync.c \
+       mbox-storage.c \
+       mbox-transaction.c
 
 noinst_HEADERS = \
        istream-raw-mbox.h \
+       mbox-file.h \
        mbox-from.h \
+       mbox-lock.h \
        mbox-storage.h \
        mbox-sync-private.h
index dbab0f778e235f04374bad867beb04eeb62c5cd4..e0f0799848ffc592fab4940e34c10786693e5acc 100644 (file)
@@ -10,7 +10,9 @@ struct raw_mbox_istream {
        struct _istream istream;
 
        time_t received_time, next_received_time;
-       uoff_t from_offset, body_size;
+       char *sender, *next_sender;
+
+       uoff_t from_offset, hdr_offset, next_from_offset, body_size;
        struct istream *input;
 };
 
@@ -42,12 +44,66 @@ static void _set_blocking(struct _iostream *stream, int timeout_msecs,
                              timeout_cb, context);
 }
 
+static int mbox_read_from_line(struct raw_mbox_istream *rstream)
+{
+       const unsigned char *buf, *p;
+       char *sender;
+       time_t received_time;
+       size_t pos, line_pos;
+       int skip;
+
+       buf = i_stream_get_data(rstream->input, &pos);
+       i_assert(pos > 0);
+
+       /* from_offset points to "\nFrom ", so unless we're at the beginning
+          of the file, skip the initial \n */
+       skip = rstream->from_offset != 0;
+
+       while ((p = memchr(buf+skip, '\n', pos-skip)) == NULL) {
+               if (i_stream_read(rstream->input) < 0) {
+                       /* EOF - shouldn't happen */
+                       return -1;
+               }
+               buf = i_stream_get_data(rstream->input, &pos);
+       }
+       line_pos = (size_t)(p - buf);
+
+       if (rstream->from_offset != 0) {
+               buf++;
+               pos--;
+       }
+
+       /* beginning of mbox */
+       if (memcmp(buf, "From ", 5) != 0 ||
+           mbox_from_parse(buf+5, pos-5, &received_time, &sender) < 0) {
+               /* broken From - should happen only at beginning of
+                  file if this isn't a mbox.. */
+               return -1;
+       }
+
+       if (rstream->istream.istream.v_offset == rstream->from_offset) {
+               rstream->received_time = received_time;
+               i_free(rstream->sender);
+               rstream->sender = sender;
+       } else {
+               rstream->next_received_time = received_time;
+               i_free(rstream->next_sender);
+               rstream->next_sender = sender;
+       }
+
+       /* we'll skip over From-line */
+       rstream->istream.istream.v_offset += line_pos+1;
+       rstream->hdr_offset = rstream->istream.istream.v_offset;
+       return 0;
+}
+
 static ssize_t _read(struct _istream *stream)
 {
        static const char *mbox_from = "\nFrom ";
        struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
-       const unsigned char *buf, *p;
+       const unsigned char *buf;
        const char *fromp;
+       char *sender;
        time_t received_time;
        size_t i, pos;
        ssize_t ret;
@@ -71,58 +127,24 @@ static ssize_t _read(struct _istream *stream)
        }
 
        if (stream->istream.v_offset == rstream->from_offset) {
-               /* read the full From-line */
-               int skip = rstream->from_offset != 0;
-               size_t line_pos;
-
-               while ((p = memchr(buf+skip, '\n', pos-skip)) == NULL) {
-                       if (i_stream_read(rstream->input) < 0) {
-                               /* EOF - shouldn't happen */
-                               stream->pos = 0;
-                               stream->istream.eof = TRUE;
-                               return -1;
-                       }
-                       buf = i_stream_get_data(rstream->input, &pos);
-               }
-               line_pos = (size_t)(p - buf);
-
-               if (rstream->from_offset != 0) {
-                       buf++;
-                       pos--;
-               }
-
-               /* beginning of mbox */
-               if (memcmp(buf, "From ", 5) != 0)
-                       received_time = (time_t)-1;
-               else
-                       received_time = mbox_from_parse_date(buf+5, pos-5);
-
-               if (received_time == (time_t)-1) {
-                       /* broken From - should happen only at beginning of
-                          file if this isn't a mbox.. */
+               if (mbox_read_from_line(rstream) < 0) {
                        stream->pos = 0;
                        stream->istream.eof = TRUE;
                        return -1;
                }
-
-               if (rstream->from_offset == 0)
-                       rstream->received_time = received_time;
-               else
-                       rstream->next_received_time = received_time;
-
-               /* we'll skip over From-line and try again */
-               stream->istream.v_offset += line_pos+1;
                return _read(stream);
        }
 
        if (pos >= 31) {
-               if (memcmp(buf, "\nFrom ", 6) == 0) {
-                       received_time = mbox_from_parse_date(buf+6, pos-6);
-                       if (received_time != (time_t)-1) {
-                               rstream->next_received_time = received_time;
-                               i_assert(stream->pos == 0);
-                               return -1;
-                       }
+               if (memcmp(buf, "\nFrom ", 6) == 0 &&
+                   mbox_from_parse(buf+6, pos-6,
+                                   &received_time, &sender) == 0) {
+                       rstream->next_received_time = received_time;
+
+                       i_free(rstream->next_sender);
+                       rstream->next_sender = sender;
+                       i_assert(stream->pos == 0);
+                       return -1;
                }
        } else if (ret == -1) {
                /* last few bytes, can't contain From-line */
@@ -194,6 +216,7 @@ static int istream_raw_mbox_is_valid_from(struct raw_mbox_istream *rstream)
        const unsigned char *data;
        size_t size;
        time_t received_time;
+       char *sender;
 
        /* minimal: "From x Thu Nov 29 22:33:52 2001" = 31 chars */
        if (i_stream_read_data(rstream->input, &data, &size, 30) == -1)
@@ -212,11 +235,12 @@ static int istream_raw_mbox_is_valid_from(struct raw_mbox_istream *rstream)
                        break;
        }
 
-       received_time = mbox_from_parse_date(data+6, size-6);
-       if (received_time == (time_t)-1)
+       if (mbox_from_parse(data+6, size-6, &received_time, &sender) < 0)
                return FALSE;
 
        rstream->next_received_time = received_time;
+       i_free(rstream->next_sender);
+       rstream->next_sender = sender;
        return TRUE;
 }
 
@@ -250,6 +274,24 @@ uoff_t istream_raw_mbox_get_size(struct istream *stream, uoff_t body_size)
        return rstream->body_size;
 }
 
+time_t istream_raw_mbox_get_received_time(struct istream *stream)
+{
+       struct raw_mbox_istream *rstream =
+               (struct raw_mbox_istream *)stream->real_stream;
+
+       (void)_read(&rstream->istream);
+       return rstream->received_time;
+}
+
+const char *istream_raw_mbox_get_sender(struct istream *stream)
+{
+       struct raw_mbox_istream *rstream =
+               (struct raw_mbox_istream *)stream->real_stream;
+
+       (void)_read(&rstream->istream);
+       return rstream->sender == NULL ? "" : rstream->sender;
+}
+
 void istream_raw_mbox_next(struct istream *stream, uoff_t body_size)
 {
        struct raw_mbox_istream *rstream =
@@ -261,10 +303,48 @@ void istream_raw_mbox_next(struct istream *stream, uoff_t body_size)
        rstream->received_time = rstream->next_received_time;
        rstream->next_received_time = (time_t)-1;
 
+       i_free(rstream->sender);
+       rstream->sender = rstream->next_sender;
+       rstream->next_sender = NULL;
+
        rstream->from_offset = stream->v_offset + body_size;
+       rstream->hdr_offset = rstream->from_offset;
+
+       /* don't clear stream->eof if we don't have to */
+       if (stream->v_offset != rstream->from_offset)
+               i_stream_seek(stream, rstream->from_offset);
        i_stream_seek(rstream->input, rstream->from_offset);
 }
 
+void istream_raw_mbox_seek(struct istream *stream, uoff_t offset)
+{
+       struct raw_mbox_istream *rstream =
+               (struct raw_mbox_istream *)stream->real_stream;
+
+       if (offset == rstream->next_from_offset) {
+               istream_raw_mbox_next(stream, (uoff_t)-1);
+               return;
+       }
+
+       if (offset == rstream->from_offset) {
+               /* back to beginning of current message */
+               offset = rstream->hdr_offset;
+       } else {
+               rstream->body_size = (uoff_t)-1;
+               rstream->received_time = (time_t)-1;
+               rstream->next_received_time = (time_t)-1;
+
+               i_free(rstream->sender);
+               rstream->sender = NULL;
+               i_free(rstream->next_sender);
+               rstream->next_sender = NULL;
+       }
+
+       rstream->from_offset = rstream->hdr_offset = offset;
+       i_stream_seek(stream, offset);
+       i_stream_seek(rstream->input, offset);
+}
+
 void istream_raw_mbox_flush(struct istream *stream)
 {
        struct raw_mbox_istream *rstream =
index 4bbe2789930606cd848994dcba57faad32203005..bc66adc16c6262fbfac832eb3181b166cc869757 100644 (file)
@@ -10,10 +10,21 @@ struct istream *i_stream_create_raw_mbox(pool_t pool, struct istream *input);
    to avoid actually reading through the whole message. */
 uoff_t istream_raw_mbox_get_size(struct istream *stream, uoff_t body_size);
 
+/* Return received time of current message, or (time_t)-1 if the timestamp is
+   broken. */
+time_t istream_raw_mbox_get_received_time(struct istream *stream);
+
+/* Return sender of current message. */
+const char *istream_raw_mbox_get_sender(struct istream *stream);
+
 /* Jump to next message. If body_size isn't (uoff_t)-1, we'll use it as
    potentially valid body size. */
 void istream_raw_mbox_next(struct istream *stream, uoff_t body_size);
 
+/* Seek to message at given offset. offset must point to beginning of
+   "\nFrom ", or 0 for beginning of file. */
+void istream_raw_mbox_seek(struct istream *stream, uoff_t offset);
+
 /* Flush all buffering. Call if you modify the mbox. */
 void istream_raw_mbox_flush(struct istream *stream);
 
diff --git a/src/lib-storage/index/mbox/mbox-expunge.c b/src/lib-storage/index/mbox/mbox-expunge.c
deleted file mode 100644 (file)
index 1ce5727..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/* Copyright (C) 2002-2003 Timo Sirainen */
-
-#if 0
-#include "lib.h"
-#include "istream.h"
-#include "ostream.h"
-#include "mbox-index.h"
-#include "mbox-storage.h"
-#include "mbox-lock.h"
-#include "index-expunge.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-
-struct mbox_expunge_context {
-       struct mail_expunge_context *ctx;
-
-        struct index_mailbox *ibox;
-       struct istream *input;
-       struct ostream *output;
-       int failed, expunges;
-
-       uoff_t from_offset, move_offset;
-};
-
-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;
-
-       mctx = index_storage_expunge_init(box, wanted_fields, expunge_all);
-       if (mctx == NULL)
-               return NULL;
-
-       /* mbox must be already opened, synced and locked at this point.
-          we just want the istream. */
-       input = mbox_get_stream(ibox->index, MAIL_LOCK_EXCLUSIVE);
-       if (input == NULL)
-               return NULL;
-
-       i_assert(ibox->index->mbox_sync_counter ==
-                ibox->index->mbox_lock_counter);
-
-       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;
-}
-
-static int mbox_move_data(struct mbox_expunge_context *ctx)
-{
-       struct istream *input;
-       const unsigned char *data;
-       size_t size;
-       int failed;
-
-       i_stream_seek(ctx->input, ctx->move_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);
-       }
-
-       if (ctx->from_offset == 0)
-               failed = o_stream_send_istream(ctx->output, ctx->input) < 0;
-       else {
-               input = i_stream_create_limit(default_pool, ctx->input,
-                                             0, ctx->from_offset);
-               failed = o_stream_send_istream(ctx->output, ctx->input) < 0;
-               i_stream_unref(input);
-       }
-
-       return !failed;
-}
-
-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 = 0;
-                       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 (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;
-               }
-       }
-
-       if (!index_storage_expunge_deinit(ctx->ctx))
-               failed = TRUE;
-
-       o_stream_unref(ctx->output);
-       i_free(ctx);
-       return !failed;
-}
-
-static int get_from_offset(struct mbox_expunge_context *ctx,
-                          struct mail_index_record *rec, uoff_t *offset_r)
-{
-       struct message_size hdr_size;
-       uoff_t offset, body_size;
-
-       if (!mbox_mail_get_location(ctx->ibox->index, rec, &offset, &body_size))
-               return FALSE;
-
-       i_stream_seek(ctx->input, offset);
-       message_get_header_size(ctx->input, &hdr_size, NULL);
-
-       *offset_r = offset + hdr_size.physical_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(ctx, 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);
-       }
-
-       return index_storage_expunge_fetch_next(ctx->ctx);
-}
-
-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, rec, &ctx->from_offset))
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-
-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 (ctx->from_offset == (uoff_t)-1) {
-               if (!get_prev_from_offset(ctx, imail->data.idx_seq))
-                       return FALSE;
-       }
-
-       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;
-       }
-
-       if (!get_from_offset(ctx, imail->data.rec, &ctx->move_offset))
-               return FALSE;
-
-       return index_storage_expunge(mail, ctx->ctx, seq_r, notify);
-}
-#endif
diff --git a/src/lib-storage/index/mbox/mbox-file.c b/src/lib-storage/index/mbox/mbox-file.c
new file mode 100644 (file)
index 0000000..24e1c08
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2003 Timo Sirainen */
+
+#include "lib.h"
+#include "istream.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "istream-raw-mbox.h"
+
+#include <sys/stat.h>
+
+int mbox_file_open(struct index_mailbox *ibox)
+{
+       struct stat st;
+       int fd;
+
+       i_assert(ibox->mbox_fd == -1);
+
+       fd = open(ibox->path, ibox->readonly ? O_RDONLY : O_RDWR);
+       if (fd == -1) {
+               mbox_set_syscall_error(ibox, "open()");
+               return -1;
+       }
+
+       if (fstat(fd, &st) < 0) {
+               mbox_set_syscall_error(ibox, "fstat()");
+               (void)close(fd);
+               return -1;
+       }
+
+       ibox->mbox_fd = fd;
+       ibox->mbox_dev = st.st_dev;
+       ibox->mbox_ino = st.st_ino;
+       return 0;
+}
+
+void mbox_file_close(struct index_mailbox *ibox)
+{
+       mbox_file_close_stream(ibox);
+
+       if (ibox->mbox_fd != -1) {
+               if (close(ibox->mbox_fd) < 0)
+                       i_error("close(mbox) failed: %m");
+               ibox->mbox_fd = -1;
+       }
+}
+
+int mbox_file_open_stream(struct index_mailbox *ibox)
+{
+       if (ibox->mbox_stream != NULL)
+               return 0;
+
+       i_assert(ibox->mbox_file_stream == NULL);
+
+       if (ibox->mbox_fd == -1) {
+               if (mbox_file_open(ibox) < 0)
+                       return -1;
+       }
+
+       if (ibox->mail_read_mmaped) {
+               ibox->mbox_file_stream =
+                       i_stream_create_mmap(ibox->mbox_fd, default_pool,
+                                            MAIL_MMAP_BLOCK_SIZE,
+                                            0, 0, FALSE);
+       } else {
+               ibox->mbox_file_stream =
+                       i_stream_create_file(ibox->mbox_fd, default_pool,
+                                            MAIL_READ_BLOCK_SIZE, FALSE);
+       }
+
+       ibox->mbox_stream =
+               i_stream_create_raw_mbox(default_pool, ibox->mbox_file_stream);
+       return 0;
+}
+
+void mbox_file_close_stream(struct index_mailbox *ibox)
+{
+       if (ibox->mbox_stream != NULL) {
+               i_stream_close(ibox->mbox_file_stream);
+               i_stream_unref(ibox->mbox_file_stream);
+               ibox->mbox_file_stream = NULL;
+
+               i_stream_unref(ibox->mbox_stream);
+               ibox->mbox_stream = NULL;
+       }
+}
diff --git a/src/lib-storage/index/mbox/mbox-file.h b/src/lib-storage/index/mbox/mbox-file.h
new file mode 100644 (file)
index 0000000..b6665ac
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __MBOX_FILE_H
+#define __MBOX_FILE_H
+
+int mbox_file_open(struct index_mailbox *ibox);
+void mbox_file_close(struct index_mailbox *ibox);
+
+int mbox_file_open_stream(struct index_mailbox *ibox);
+void mbox_file_close_stream(struct index_mailbox *ibox);
+
+#endif
index 29dc337b663b1aee26db910c9f4cd195c1854f39..95fd7c08ba26ac7d7c37e40fa894f96469be7be6 100644 (file)
@@ -17,22 +17,28 @@ static const char *months[] = {
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 };
 
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
+int mbox_from_parse(const unsigned char *msg, size_t size,
+                   time_t *time_r, char **sender_r)
 {
-       const unsigned char *msg_end;
+       const unsigned char *msg_start, *sender_end, *msg_end;
        struct tm tm;
        int i, timezone;
        time_t t;
 
+       *time_r = (time_t)-1;
+       *sender_r = NULL;
+
        /* <sender> <date> <moreinfo> */
+       msg_start = msg;
        msg_end = msg + size;
 
-       /* skip sender */
+       /* get sender */
        while (msg < msg_end && *msg != ' ') {
                if (*msg == '\r' || *msg == '\n')
-                       return (time_t)-1;
+                       return -1;
                msg++;
        }
+       sender_end = msg;
        while (msg < msg_end && *msg == ' ') msg++;
 
        /* next 24 chars should be in the date in asctime() format, eg.
@@ -43,7 +49,7 @@ time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
           "Thu Nov 29 22:33:52 EEST 2001"
        */
        if (msg+24 > msg_end)
-               return (time_t)-1;
+               return -1;
 
        memset(&tm, 0, sizeof(tm));
 
@@ -64,17 +70,17 @@ time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
        }
 
        if (i == 12 || msg[3] != ' ')
-               return (time_t)-1;
+               return -1;
        msg += 4;
 
        /* day */
        if (msg[0] == ' ') {
                if (!i_isdigit(msg[1]) || msg[2] != ' ')
-                       return (time_t)-1;
+                       return -1;
                tm.tm_mday = msg[1]-'0';
        } else {
                if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
-                       return (time_t)-1;
+                       return -1;
                tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0');
        }
        if (tm.tm_mday == 0)
@@ -83,19 +89,19 @@ time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
 
        /* hour */
        if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
-               return (time_t)-1;
+               return -1;
        tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0');
        msg += 3;
 
        /* minute */
        if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
-               return (time_t)-1;
+               return -1;
        tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0');
        msg += 3;
 
        /* second */
        if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
-               return (time_t)-1;
+               return -1;
        tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0');
        msg += 3;
 
@@ -105,18 +111,18 @@ time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
                /* skip to next space */
                while (msg < msg_end && *msg != ' ') {
                        if (*msg == '\r' || *msg == '\n')
-                               return (time_t)-1;
+                               return -1;
                        msg++;
                }
                if (msg+5 > msg_end)
-                       return (time_t)-1;
+                       return -1;
                msg++;
        }
 
        /* year */
        if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
            !i_isdigit(msg[2]) || !i_isdigit(msg[3]))
-               return (time_t)-1;
+               return -1;
 
        tm.tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 +
                (msg[2]-'0') * 10 + (msg[3]-'0') - 1900;
@@ -132,14 +138,17 @@ time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
 
                t = utc_mktime(&tm);
                if (t == (time_t)-1)
-                       return (time_t)-1;
+                       return -1;
 
                t -= timezone * 60;
-               return t;
+               *time_r = t;
        } else {
                /* assume local timezone */
-               return mktime(&tm);
+               *time_r = mktime(&tm);
        }
+
+       *sender_r = i_strdup_until(msg_start, sender_end);
+       return 0;
 }
 
 const char *mbox_from_create(const char *sender, time_t time)
index 73f2c7fe423c6af2f7b5d61ae0f337a582c0c592..d58c7408da5c991a31228f9527bfea7be0923a2e 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef __MBOX_FROM_H
 #define __MBOX_FROM_H
 
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size);
+int mbox_from_parse(const unsigned char *msg, size_t size,
+                   time_t *time_r, char **sender_r);
 const char *mbox_from_create(const char *sender, time_t time);
 
 #endif
index d29cfaaa8231daed3c482a21f0eabd46391e82d2..3c51352b5c0651a7b7d421d516fd1f713ba898d0 100644 (file)
@@ -1,11 +1,9 @@
 /* Copyright (C) 2002-2003 Timo Sirainen */
 
-#if 0
 #include "lib.h"
 #include "unlink-directory.h"
 #include "imap-match.h"
 #include "subscription-file/subscription-file.h"
-#include "mbox-index.h"
 #include "mbox-storage.h"
 #include "home-expand.h"
 
@@ -27,8 +25,10 @@ struct list_dir_context {
        char *real_path, *virtual_path;
 };
 
-struct mailbox_list_context {
-       struct mail_storage *storage;
+struct mbox_list_context {
+       struct mailbox_list_context mailbox_ctx;
+       struct index_storage *istorage;
+
        enum mailbox_list_flags flags;
 
        const char *prefix;
@@ -37,18 +37,18 @@ struct mailbox_list_context {
 
        int failed;
 
-       struct mailbox_list *(*next)(struct mailbox_list_context *ctx);
+       struct mailbox_list *(*next)(struct mbox_list_context *ctx);
 
        pool_t list_pool;
        struct mailbox_list list;
         struct list_dir_context *dir;
 };
 
-static struct mailbox_list *mbox_list_subs(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_inbox(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_path(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_next(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_none(struct mailbox_list_context *ctx);
+static struct mailbox_list *mbox_list_subs(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_inbox(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_path(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_next(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_none(struct mbox_list_context *ctx);
 
 static const char *mask_get_dir(struct mail_storage *storage, const char *mask)
 {
@@ -72,7 +72,8 @@ static const char *mask_get_dir(struct mail_storage *storage, const char *mask)
        return last_dir == NULL ? NULL : t_strdup_until(mask, last_dir);
 }
 
-static const char *mbox_get_path(struct mail_storage *storage, const char *name)
+static const char *
+mbox_get_path(struct index_storage *storage, const char *name)
 {
        if (!full_filesystem_access || name == NULL ||
            (*name != '/' && *name != '~' && *name != '\0'))
@@ -109,10 +110,11 @@ static int list_opendir(struct mail_storage *storage,
 }
 
 struct mailbox_list_context *
-mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
+mbox_mailbox_list_init(struct mail_storage *storage, const char *mask,
                       enum mailbox_list_flags flags)
 {
-       struct mailbox_list_context *ctx;
+       struct index_storage *istorage = (struct index_storage *)storage;
+       struct mbox_list_context *ctx;
        const char *path, *virtual_path;
        DIR *dirp;
 
@@ -120,13 +122,13 @@ mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
 
        if (storage->hierarchy_sep != '/' && strchr(mask, '/') != NULL) {
                /* this will never match, return nothing */
-               ctx = i_new(struct mailbox_list_context, 1);
-               ctx->storage = storage;
+               ctx = i_new(struct mbox_list_context, 1);
+               ctx->mailbox_ctx.storage = storage;
                 ctx->next = mbox_list_none;
-               return ctx;
+               return &ctx->mailbox_ctx;
        }
 
-       mask = mbox_fix_mailbox_name(storage, mask, FALSE);
+       mask = mbox_fix_mailbox_name(istorage, mask, FALSE);
 
        /* check that we're not trying to do any "../../" lists */
        if (!mbox_is_valid_mask(mask)) {
@@ -135,36 +137,39 @@ mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
        }
 
        if ((flags & MAILBOX_LIST_SUBSCRIBED) != 0) {
-               ctx = i_new(struct mailbox_list_context, 1);
-               ctx->storage = storage;
+               ctx = i_new(struct mbox_list_context, 1);
+               ctx->mailbox_ctx.storage = storage;
+               ctx->istorage = istorage;
                ctx->flags = flags;
                ctx->next = mbox_list_subs;
-               ctx->subsfile_ctx = subsfile_list_init(storage);
+               ctx->subsfile_ctx =
+                       subsfile_list_init(storage, SUBSCRIPTION_FILE_NAME);
                if (ctx->subsfile_ctx == NULL) {
                        i_free(ctx);
                        return NULL;
                }
                ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
                ctx->list_pool = pool_alloconly_create("mbox_list", 1024);
-               return ctx;
+               return &ctx->mailbox_ctx;
        }
 
        /* if we're matching only subdirectories, don't bother scanning the
           parent directories */
        virtual_path = mask_get_dir(storage, mask);
 
-       path = mbox_get_path(storage, virtual_path);
+       path = mbox_get_path(istorage, virtual_path);
        if (list_opendir(storage, path, TRUE, &dirp) < 0)
                return NULL;
        /* if user gave invalid directory, we just don't show any results. */
 
-       ctx = i_new(struct mailbox_list_context, 1);
-       ctx->storage = storage;
+       ctx = i_new(struct mbox_list_context, 1);
+       ctx->mailbox_ctx.storage = storage;
+       ctx->istorage = istorage;
        ctx->flags = flags;
        ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
        ctx->list_pool = pool_alloconly_create("mbox_list", 1024);
        ctx->prefix = storage->namespace == NULL ? "" :
-               mbox_fix_mailbox_name(storage, storage->namespace, FALSE);
+               mbox_fix_mailbox_name(istorage, storage->namespace, FALSE);
 
        if (virtual_path == NULL && imap_match(ctx->glob, "INBOX") > 0)
                ctx->next = mbox_list_inbox;
@@ -180,7 +185,7 @@ mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
                ctx->dir->virtual_path = virtual_path == NULL ? NULL :
                        i_strconcat(ctx->prefix, virtual_path, NULL);
        }
-       return ctx;
+       return &ctx->mailbox_ctx;
 }
 
 static void list_dir_context_free(struct list_dir_context *dir)
@@ -191,13 +196,14 @@ static void list_dir_context_free(struct list_dir_context *dir)
        i_free(dir);
 }
 
-int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx)
+int mbox_mailbox_list_deinit(struct mailbox_list_context *_ctx)
 {
-       int failed = ctx->failed;
+       struct mbox_list_context *ctx = (struct mbox_list_context *)_ctx;
+       int ret = ctx->failed ? -1 : 0;
 
        if (ctx->subsfile_ctx != NULL) {
-               if (!subsfile_list_deinit(ctx->subsfile_ctx))
-                       failed = TRUE;
+               if (subsfile_list_deinit(ctx->subsfile_ctx) < 0)
+                       ret = -1;
        }
 
        while (ctx->dir != NULL) {
@@ -213,15 +219,17 @@ int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx)
                imap_match_deinit(ctx->glob);
        i_free(ctx);
 
-       return !failed;
+       return ret;
 }
 
-struct mailbox_list *mbox_list_mailbox_next(struct mailbox_list_context *ctx)
+struct mailbox_list *mbox_mailbox_list_next(struct mailbox_list_context *_ctx)
 {
+       struct mbox_list_context *ctx = (struct mbox_list_context *)_ctx;
+
        return ctx->next(ctx);
 }
 
-static int list_file(struct mailbox_list_context *ctx, const char *fname)
+static int list_file(struct mbox_list_context *ctx, const char *fname)
 {
         struct list_dir_context *dir;
        const char *list_path, *real_path, *path;
@@ -260,8 +268,8 @@ static int list_file(struct mailbox_list_context *ctx, const char *fname)
        else {
                if (ENOTFOUND(errno))
                        return 0;
-               mail_storage_set_critical(ctx->storage, "stat(%s) failed: %m",
-                                         real_path);
+               mail_storage_set_critical(ctx->mailbox_ctx.storage,
+                                         "stat(%s) failed: %m", real_path);
                return -1;
        }
 
@@ -279,7 +287,8 @@ static int list_file(struct mailbox_list_context *ctx, const char *fname)
                        ctx->list.name = NULL;
 
                ret = match2 < 0 ? 0 :
-                       list_opendir(ctx->storage, real_path, FALSE, &dirp);
+                       list_opendir(ctx->mailbox_ctx.storage,
+                                    real_path, FALSE, &dirp);
                if (ret > 0) {
                        dir = i_new(struct list_dir_context, 1);
                        dir->dirp = dirp;
@@ -292,7 +301,7 @@ static int list_file(struct mailbox_list_context *ctx, const char *fname)
                        return -1;
                return match > 0 || match2 > 0;
        } else if (match > 0 &&
-                  strcmp(real_path, ctx->storage->inbox_file) != 0 &&
+                  strcmp(real_path, ctx->istorage->inbox_path) != 0 &&
                   strcasecmp(list_path, "INBOX") != 0) {
                /* don't match any INBOX here, it's added separately.
                   we might also have ~/mail/inbox, ~/mail/Inbox etc.
@@ -306,7 +315,7 @@ static int list_file(struct mailbox_list_context *ctx, const char *fname)
        return 0;
 }
 
-static struct mailbox_list *list_fix_name(struct mailbox_list_context *ctx)
+static struct mailbox_list *list_fix_name(struct mbox_list_context *ctx)
 {
        char *p, *str, sep;
 
@@ -314,7 +323,7 @@ static struct mailbox_list *list_fix_name(struct mailbox_list_context *ctx)
                str = p_strdup(ctx->list_pool, ctx->list.name);
                ctx->list.name = str;
 
-               sep = ctx->storage->hierarchy_sep;
+               sep = ctx->mailbox_ctx.storage->hierarchy_sep;
                for (p = str; *p != '\0'; p++) {
                        if (*p == '/')
                                *p = sep;
@@ -324,7 +333,7 @@ static struct mailbox_list *list_fix_name(struct mailbox_list_context *ctx)
        return &ctx->list;
 }
 
-static struct mailbox_list *mbox_list_subs(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_subs(struct mbox_list_context *ctx)
 {
        struct stat st;
        const char *name, *path, *p;
@@ -361,8 +370,8 @@ static struct mailbox_list *mbox_list_subs(struct mailbox_list_context *ctx)
                return &ctx->list;
 
        t_push();
-       name = mbox_fix_mailbox_name(ctx->storage, ctx->list.name, TRUE);
-       path = mbox_get_path(ctx->storage, name);
+       name = mbox_fix_mailbox_name(ctx->istorage, ctx->list.name, TRUE);
+       path = mbox_get_path(ctx->istorage, name);
        if (stat(path, &st) == 0) {
                if (S_ISDIR(st.st_mode))
                        ctx->list.flags = MAILBOX_NOSELECT | MAILBOX_CHILDREN;
@@ -380,7 +389,7 @@ static struct mailbox_list *mbox_list_subs(struct mailbox_list_context *ctx)
        return &ctx->list;
 }
 
-static struct mailbox_list *mbox_list_inbox(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_inbox(struct mbox_list_context *ctx)
 {
        struct stat st;
 
@@ -393,7 +402,7 @@ static struct mailbox_list *mbox_list_inbox(struct mailbox_list_context *ctx)
        ctx->list.flags = strncmp(ctx->prefix, "INBOX/", 6) == 0 ?
                MAILBOX_CHILDREN : MAILBOX_NOINFERIORS;
        if ((ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0) {
-               if (stat(ctx->storage->inbox_file, &st) < 0)
+               if (stat(ctx->istorage->inbox_path, &st) < 0)
                        ctx->list.flags |= MAILBOX_UNMARKED;
                else
                        ctx->list.flags |= STAT_GET_MARKED(st);
@@ -403,7 +412,7 @@ static struct mailbox_list *mbox_list_inbox(struct mailbox_list_context *ctx)
        return &ctx->list;
 }
 
-static struct mailbox_list *mbox_list_path(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_path(struct mbox_list_context *ctx)
 {
        ctx->next = mbox_list_next;
 
@@ -417,7 +426,7 @@ static struct mailbox_list *mbox_list_path(struct mailbox_list_context *ctx)
                return ctx->next(ctx);
 }
 
-static struct mailbox_list *mbox_list_next(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_next(struct mbox_list_context *ctx)
 {
        struct list_dir_context *dir;
        struct dirent *d;
@@ -450,8 +459,7 @@ static struct mailbox_list *mbox_list_next(struct mailbox_list_context *ctx)
 }
 
 static struct mailbox_list *
-mbox_list_none(struct mailbox_list_context *ctx __attr_unused__)
+mbox_list_none(struct mbox_list_context *ctx __attr_unused__)
 {
        return NULL;
 }
-#endif
diff --git a/src/lib-storage/index/mbox/mbox-lock.c b/src/lib-storage/index/mbox/mbox-lock.c
new file mode 100644 (file)
index 0000000..4857540
--- /dev/null
@@ -0,0 +1,318 @@
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "lib.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "mbox-lock.h"
+
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_FLOCK
+#  include <sys/file.h>
+#endif
+
+/* 0.1 .. 0.2msec */
+#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
+
+/* lock methods to use in wanted order */
+#define DEFAULT_LOCK_METHODS "dotlock fcntl"
+/* lock timeout */
+#define DEFAULT_LOCK_TIMEOUT 300
+/* assume stale dotlock if mbox file hasn't changed for n seconds */
+#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT 30
+
+struct dotlock_context {
+        struct index_mailbox *ibox;
+        int lock_type;
+       int last_stale;
+};
+
+static int lock_settings_initialized = FALSE;
+static int use_dotlock, use_fcntl_lock, use_flock, fcntl_before_flock;
+static int use_read_dotlock, lock_timeout, dotlock_change_timeout;
+
+static int mbox_unlock_files(struct index_mailbox *ibox);
+
+static void mbox_init_lock_settings(void)
+{
+       const char *str;
+       const char *const *lock;
+
+        use_dotlock = use_fcntl_lock = use_flock = fcntl_before_flock = FALSE;
+
+       str = getenv("MBOX_LOCKS");
+       if (str == NULL) str = DEFAULT_LOCK_METHODS;
+       for (lock = t_strsplit(str, " "); *lock != NULL; lock++) {
+               if (strcasecmp(*lock, "dotlock") == 0)
+                       use_dotlock = TRUE;
+               else if (strcasecmp(*lock, "fcntl") == 0) {
+                       use_fcntl_lock = TRUE;
+                       fcntl_before_flock = use_flock == FALSE;
+               } else if (strcasecmp(*lock, "flock") == 0)
+                       use_flock = TRUE;
+               else
+                       i_fatal("MBOX_LOCKS: Invalid value %s", *lock);
+       }
+
+       use_read_dotlock = getenv("MBOX_READ_DOTLOCK") != NULL;
+
+       str = getenv("MBOX_LOCK_TIMEOUT");
+       lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
+
+       str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
+       dotlock_change_timeout = str == NULL ?
+               DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
+
+        lock_settings_initialized = TRUE;
+}
+
+#ifdef HAVE_FLOCK
+static int mbox_lock_flock(struct index_mailbox *ibox, int lock_type,
+                          time_t max_wait_time)
+{
+       time_t now, last_notify;
+
+       if (lock_type == F_WRLCK)
+               lock_type = LOCK_EX;
+       else if (lock_type == F_RDLCK)
+               lock_type = LOCK_SH;
+       else
+               lock_type = LOCK_UN;
+
+        last_notify = 0;
+       while (flock(ibox->mbox_fd, lock_type | LOCK_NB) < 0) {
+               if (errno != EWOULDBLOCK) {
+                       mbox_set_syscall_error(ibox, "flock()");
+                       return -1;
+               }
+
+               if (max_wait_time == 0)
+                       return 0;
+
+               now = time(NULL);
+               if (now >= max_wait_time)
+                       return 0;
+
+               if (now != last_notify) {
+                       index_storage_lock_notify(ibox,
+                               MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+                               max_wait_time - now);
+               }
+
+               usleep(LOCK_RANDOM_USLEEP_TIME);
+       }
+
+       return 1;
+}
+#endif
+
+static int mbox_lock_fcntl(struct index_mailbox *ibox, int lock_type,
+                          time_t max_wait_time)
+{
+       struct flock fl;
+       time_t now;
+       int wait_type;
+
+       fl.l_type = lock_type;
+       fl.l_whence = SEEK_SET;
+       fl.l_start = 0;
+       fl.l_len = 0;
+
+        wait_type = max_wait_time == 0 ? F_SETLK : F_SETLKW;
+       while (fcntl(ibox->mbox_fd, wait_type, &fl) < 0) {
+               if (errno != EINTR) {
+                       if (errno != EAGAIN && errno != EACCES)
+                               mbox_set_syscall_error(ibox, "fcntl()");
+                       return -1;
+               }
+
+               now = time(NULL);
+               if (max_wait_time != 0 && now >= max_wait_time)
+                       return 0;
+
+               index_storage_lock_notify(ibox,
+                                         MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+                                         max_wait_time - now);
+       }
+
+       return 1;
+}
+
+static int mbox_file_locks(struct index_mailbox *ibox, int lock_type,
+                          time_t max_wait_time)
+{
+       struct stat st;
+       int ret;
+
+       /* now we need to have the file itself locked. open it if needed. */
+       if (stat(ibox->path, &st) < 0) {
+               mbox_set_syscall_error(ibox, "stat()");
+               return -1;
+       }
+
+       if (st.st_dev != ibox->mbox_dev || st.st_ino != ibox->mbox_ino)
+               mbox_file_close(ibox);
+
+       if (ibox->mbox_fd == -1) {
+               if (mbox_file_open(ibox) < 0) {
+                       (void)mbox_unlock_files(ibox);
+                       return -1;
+               }
+       }
+
+       if (use_fcntl_lock && fcntl_before_flock) {
+               ret = mbox_lock_fcntl(ibox, lock_type, max_wait_time);
+               if (ret <= 0)
+                       return ret;
+       }
+#ifdef HAVE_FLOCK
+       if (use_flock) {
+               ret = mbox_lock_flock(ibox, lock_type, max_wait_time);
+               if (ret <= 0)
+                       return ret;
+       }
+#endif
+       if (use_fcntl_lock && !fcntl_before_flock) {
+               ret = mbox_lock_fcntl(ibox, lock_type, max_wait_time);
+               if (ret <= 0)
+                       return ret;
+       }
+       return 1;
+}
+
+static int mbox_file_unlock(struct index_mailbox *ibox)
+{
+       int ret = 0;
+
+#ifdef HAVE_FLOCK
+       if (use_flock && mbox_lock_flock(ibox, F_UNLCK, 0) < 0)
+               ret = -1;
+#endif
+       if (use_fcntl_lock && mbox_lock_fcntl(ibox, F_UNLCK, 0) < 0)
+               ret = -1;
+
+       return ret;
+}
+
+static int dotlock_callback(unsigned int secs_left, int stale, void *context)
+{
+       struct dotlock_context *ctx = context;
+
+       if (stale && !ctx->last_stale) {
+               if (mbox_file_locks(ctx->ibox, ctx->lock_type, 0) <= 0) {
+                       /* we couldn't get fcntl/flock - it's really locked */
+                       ctx->last_stale = TRUE;
+                       return FALSE;
+               }
+               (void)mbox_file_unlock(ctx->ibox);
+       }
+       ctx->last_stale = stale;
+
+       index_storage_lock_notify(ctx->ibox, stale ?
+                                 MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
+                                 MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+                                 secs_left);
+       return TRUE;
+}
+
+int mbox_lock(struct index_mailbox *ibox, int lock_type,
+             unsigned int *lock_id_r)
+{
+       time_t max_wait_time;
+       int ret;
+
+       /* allow only unlock -> shared/exclusive or exclusive -> shared */
+       i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
+       i_assert(lock_type == F_RDLCK || ibox->mbox_lock_type != F_RDLCK);
+
+       if (ibox->mbox_lock_type == lock_type) {
+               ibox->mbox_locks++;
+               return 1;
+       }
+
+        index_storage_lock_notify_reset(ibox);
+
+       if (!lock_settings_initialized)
+                mbox_init_lock_settings();
+
+       max_wait_time = time(NULL) + lock_timeout;
+
+       /* make .lock file first to protect overwriting the file */
+       if (use_dotlock && ibox->mbox_dotlock.ino == 0) {
+               struct dotlock_context ctx;
+
+               ctx.ibox = ibox;
+               ctx.lock_type = lock_type;
+               ctx.last_stale = -1;
+
+               ret = file_lock_dotlock(ibox->path, NULL,
+                                       lock_type == F_RDLCK &&
+                                       !use_read_dotlock, lock_timeout,
+                                       dotlock_change_timeout, 0,
+                                       dotlock_callback, &ctx,
+                                       &ibox->mbox_dotlock);
+
+               if (ret < 0) {
+                       mbox_set_syscall_error(ibox, "file_lock_dotlock()");
+                       return -1;
+               }
+               if (ret == 0) {
+                       mail_storage_set_error(ibox->box.storage,
+                               "Timeout while waiting for lock");
+                       return 0;
+               }
+       }
+
+       ibox->mbox_lock_type = lock_type;
+       ret = mbox_file_locks(ibox, ibox->mbox_lock_type, max_wait_time);
+       if (ret <= 0) {
+               (void)mbox_unlock_files(ibox);
+               if (ret == 0) {
+                       mail_storage_set_error(ibox->box.storage,
+                               "Timeout while waiting for lock");
+               }
+               return ret;
+       }
+
+       *lock_id_r = ++ibox->mbox_lock_id;
+       return 1;
+}
+
+static int mbox_unlock_files(struct index_mailbox *ibox)
+{
+       int ret = 0;
+
+       if (ibox->mbox_fd != -1) {
+               if (mbox_file_unlock(ibox) < 0)
+                       ret = -1;
+       }
+
+       if (ibox->mbox_dotlock.ino != 0) {
+               if (file_unlock_dotlock(ibox->path, &ibox->mbox_dotlock) <= 0) {
+                       mbox_set_syscall_error(ibox, "file_unlock_dotlock()");
+                       ret = -1;
+               }
+                ibox->mbox_dotlock.ino = 0;
+       }
+
+       /* make sure we don't keep mmap() between locks */
+       mbox_file_close_stream(ibox);
+
+       ibox->mbox_lock_id++;
+       ibox->mbox_lock_type = F_UNLCK;
+       return ret;
+}
+
+int mbox_unlock(struct index_mailbox *ibox, unsigned int lock_id)
+{
+       i_assert(ibox->mbox_lock_id == lock_id);
+
+       if (--ibox->mbox_locks > 0)
+               return 0;
+
+       return mbox_unlock_files(ibox);
+}
diff --git a/src/lib-storage/index/mbox/mbox-lock.h b/src/lib-storage/index/mbox/mbox-lock.h
new file mode 100644 (file)
index 0000000..598060f
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __MBOX_LOCK_H
+#define __MBOX_LOCK_H
+
+/* NOTE: if mbox file is not open, it's opened. if it is open but file has
+   been overwritten (ie. inode has changed), it's reopened. */
+int mbox_lock(struct index_mailbox *ibox, int lock_type,
+             unsigned int *lock_id_r);
+int mbox_unlock(struct index_mailbox *ibox, unsigned int lock_id);
+
+#endif
diff --git a/src/lib-storage/index/mbox/mbox-mail.c b/src/lib-storage/index/mbox/mbox-mail.c
new file mode 100644 (file)
index 0000000..f8a2d8f
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright (C) 2003 Timo Sirainen */
+
+#include "lib.h"
+#include "istream.h"
+#include "index-mail.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "istream-raw-mbox.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int mbox_mail_seek(struct index_mail *mail)
+{
+       i_assert(mail->mail.seq <= mail->ibox->mbox_data_count);
+
+       // FIXME: lock the file
+
+       if (mbox_file_open_stream(mail->ibox) < 0)
+               return -1;
+
+       i_stream_seek(mail->ibox->mbox_stream,
+                     mail->ibox->mbox_data[mail->mail.seq-1] >> 1);
+       return 0;
+}
+
+static const struct mail_full_flags *mbox_mail_get_flags(struct mail *_mail)
+{
+       struct index_mail *mail = (struct index_mail *)_mail;
+       struct index_mail_data *data = &mail->data;
+
+       i_assert(_mail->seq <= mail->ibox->mbox_data_count);
+
+       (void)index_mail_get_flags(_mail);
+       if ((mail->ibox->mbox_data[_mail->seq-1] & 1) != 0)
+               data->flags.flags |= MAIL_RECENT;
+
+       return &data->flags;
+}
+
+static time_t mbox_mail_get_received_date(struct mail *_mail)
+{
+       struct index_mail *mail = (struct index_mail *)_mail;
+       struct index_mail_data *data = &mail->data;
+
+       (void)index_mail_get_received_date(_mail);
+       if (data->received_date != (time_t)-1)
+               return data->received_date;
+
+       if (mbox_mail_seek(mail) < 0)
+               return (time_t)-1;
+       data->received_date =
+               istream_raw_mbox_get_received_time(mail->ibox->mbox_stream);
+
+       if (data->received_date != (time_t)-1) {
+               index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE,
+                                    &data->received_date,
+                                    sizeof(data->received_date));
+       }
+       return data->received_date;
+}
+
+static const char *
+mbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field)
+{
+       struct index_mail *mail = (struct index_mail *)_mail;
+
+       if (field == MAIL_FETCH_FROM_ENVELOPE) {
+               if (mbox_mail_seek(mail) < 0)
+                       return NULL;
+
+               return istream_raw_mbox_get_sender(mail->ibox->mbox_stream);
+
+       }
+
+       return index_mail_get_special(_mail, field);
+}
+
+static struct istream *mbox_mail_get_stream(struct mail *_mail,
+                                           struct message_size *hdr_size,
+                                           struct message_size *body_size)
+{
+       struct index_mail *mail = (struct index_mail *)_mail;
+       struct index_mail_data *data = &mail->data;
+
+       if (data->stream == NULL) {
+               if (mbox_mail_seek(mail) < 0)
+                       return NULL;
+
+               data->stream = mail->ibox->mbox_stream;
+       }
+
+       return index_mail_init_stream(mail, hdr_size, body_size);
+}
+
+struct mail mbox_mail = {
+       0, 0, 0, 0, 0, 0,
+
+       mbox_mail_get_flags,
+       index_mail_get_parts,
+       mbox_mail_get_received_date,
+       index_mail_get_date,
+       index_mail_get_size,
+       index_mail_get_header,
+       index_mail_get_headers,
+       mbox_mail_get_stream,
+       mbox_mail_get_special,
+       index_mail_update_flags,
+       index_mail_expunge
+};
index f8c9ac4c25109dc09465112903b0a9ebfa1fb7e5..9c6483a5d13ac9fa7d559922148022693e4b4afc 100644 (file)
@@ -1,14 +1,14 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
-#if 0
 #include "lib.h"
 #include "hostpid.h"
 #include "ostream.h"
 #include "str.h"
 #include "write-full.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
 #include "mbox-storage.h"
+#include "mbox-file.h"
+#include "mbox-from.h"
+#include "mbox-lock.h"
 #include "mail-save.h"
 
 #include <stdlib.h>
@@ -17,9 +17,9 @@
 #include <sys/stat.h>
 #include <netdb.h>
 
-struct mail_save_context {
+struct mbox_save_context {
        struct index_mailbox *ibox;
-       int transaction;
+       uoff_t append_offset;
 
        struct ostream *output;
        uoff_t sync_offset, content_length_offset, eoh_offset;
@@ -29,45 +29,37 @@ struct mail_save_context {
 
 static char my_hostdomain[256] = "";
 
-static int syscall_error(struct mail_save_context *ctx, const char *function)
-{
-       mail_storage_set_critical(ctx->ibox->box.storage,
-                                 "%s failed for mbox file %s: %m",
-                                 function, ctx->ibox->index->mailbox_path);
-       return FALSE;
-}
-
-static int write_error(struct mail_save_context *ctx)
+static int write_error(struct mbox_save_context *ctx)
 {
        if (ENOSPACE(errno)) {
                mail_storage_set_error(ctx->ibox->box.storage,
                                       "Not enough disk space");
        } else {
-                syscall_error(ctx, "write()");
+                mbox_set_syscall_error(ctx->ibox, "write()");
        }
 
-       return FALSE;
+       return -1;
 }
 
-static int mbox_seek_to_end(struct mail_save_context *ctx, uoff_t *offset)
+static int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
 {
        struct stat st;
        char ch;
        int fd;
 
-       fd = ctx->ibox->index->mbox_fd;
+       fd = ctx->ibox->mbox_fd;
        if (fstat(fd, &st) < 0)
-                return syscall_error(ctx, "fstat()");
+                return mbox_set_syscall_error(ctx->ibox, "fstat()");
 
        *offset = (uoff_t)st.st_size;
        if (st.st_size == 0)
-               return TRUE;
+               return 0;
 
        if (lseek(fd, st.st_size-1, SEEK_SET) < 0)
-                return syscall_error(ctx, "lseek()");
+                return mbox_set_syscall_error(ctx->ibox, "lseek()");
 
        if (read(fd, &ch, 1) != 1)
-               return syscall_error(ctx, "read()");
+               return mbox_set_syscall_error(ctx->ibox, "read()");
 
        if (ch != '\n') {
                if (write_full(fd, "\n", 1) < 0)
@@ -75,10 +67,10 @@ static int mbox_seek_to_end(struct mail_save_context *ctx, uoff_t *offset)
                *offset += 1;
        }
 
-       return TRUE;
+       return 0;
 }
 
-static int mbox_append_lf(struct mail_save_context *ctx)
+static int mbox_append_lf(struct mbox_save_context *ctx)
 {
        if (o_stream_send(ctx->output, "\n", 1) < 0)
                return write_error(ctx);
@@ -86,9 +78,10 @@ static int mbox_append_lf(struct mail_save_context *ctx)
        return TRUE;
 }
 
-static int write_from_line(struct mail_save_context *ctx, time_t received_date)
+static int write_from_line(struct mbox_save_context *ctx, time_t received_date,
+                          const char *from_envelope)
 {
-       const char *sender, *line, *name;
+       const char *line, *name;
 
        if (*my_hostdomain == '\0') {
                struct hostent *hent;
@@ -104,16 +97,18 @@ static int write_from_line(struct mail_save_context *ctx, time_t received_date)
                strocpy(my_hostdomain, name, sizeof(my_hostdomain));
        }
 
-       sender = t_strconcat(ctx->ibox->box.storage->user, "@",
-                            my_hostdomain, NULL);
+       if (from_envelope == NULL) {
+               from_envelope = t_strconcat(ctx->ibox->storage->user, "@",
+                                           my_hostdomain, NULL);
+       }
 
        /* save in local timezone, no matter what it was given with */
-       line = mbox_from_create(sender, received_date);
+       line = mbox_from_create(from_envelope, received_date);
 
        if (o_stream_send_str(ctx->output, line) < 0)
                return write_error(ctx);
 
-       return TRUE;
+       return 0;
 }
 
 static const char *get_system_flags(enum mail_flags flags)
@@ -147,25 +142,17 @@ static const char *get_system_flags(enum mail_flags flags)
 static const char *get_keywords(const struct mail_full_flags *flags)
 {
        string_t *str;
-       unsigned int field;
        unsigned int i;
 
-       if ((flags->flags & MAIL_KEYWORDS_MASK) == 0)
+       if (flags->keywords_count == 0)
                return "";
 
        str = t_str_new(256);
-       field = 1 << MAIL_KEYWORD_1_BIT;
        for (i = 0; i < flags->keywords_count; i++) {
-               const char *keyword = flags->keywords[i];
-
-               if ((flags->flags & field) && keyword != NULL) {
+               if (str_len(str) > 0)
                        str_append_c(str, ' ');
-                       str_append(str, keyword);
-               }
-
-               field <<= 1;
+               str_append(str, flags->keywords[i]);
        }
-
        return str_c(str);
 }
 
@@ -173,7 +160,7 @@ static int save_header_callback(const char *name, write_func_t *write_func,
                                void *context)
 {
        static const char *content_length = "Content-Length: ";
-       struct mail_save_context *ctx = context;
+       struct mbox_save_context *ctx = context;
        const char *str;
        char *buf;
        size_t space;
@@ -238,7 +225,7 @@ static int save_header_callback(const char *name, write_func_t *write_func,
        return 1;
 }
 
-static int mbox_fix_header(struct mail_save_context *ctx)
+static int mbox_fix_header(struct mbox_save_context *ctx)
 {
        uoff_t old_offset;
        const char *str;
@@ -246,7 +233,7 @@ static int mbox_fix_header(struct mail_save_context *ctx)
 
        old_offset = ctx->output->offset;
        if (o_stream_seek(ctx->output, ctx->content_length_offset) < 0)
-                return syscall_error(ctx, "o_stream_seek()");
+                return mbox_set_syscall_error(ctx->ibox, "o_stream_seek()");
 
        /* write value for Content-Length */
        str = dec2str(old_offset - (ctx->eoh_offset + 1 + crlf));
@@ -264,112 +251,102 @@ static int mbox_fix_header(struct mail_save_context *ctx)
                return write_error(ctx);
 
        if (o_stream_seek(ctx->output, old_offset) < 0)
-               return syscall_error(ctx, "o_stream_seek()");
-       return TRUE;
+               return mbox_set_syscall_error(ctx->ibox, "o_stream_seek()");
+       return 0;
 }
 
-int mbox_storage_save_next(struct mail_save_context *ctx,
-                          const struct mail_full_flags *flags,
-                          time_t received_date,
-                          int timezone_offset __attr_unused__,
-                          struct istream *data)
+int mbox_save(struct mailbox_transaction_context *_t,
+             const struct mail_full_flags *flags,
+             time_t received_date, int timezone_offset __attr_unused__,
+             const char *from_envelope, struct istream *data)
 {
-       enum mail_flags real_flags;
-       int failed;
+       struct mbox_transaction_context *t =
+               (struct mbox_transaction_context *)_t;
+       struct index_mailbox *ibox = t->ictx.ibox;
+       struct mbox_save_context *ctx = t->save_ctx;
+       int ret;
 
-       /* we don't need the real flag positions, easier to keep using our own.
-          they need to be checked/added though. */
        ctx->flags = flags;
-       real_flags = flags->flags;
-       if (!index_mailbox_fix_keywords(ctx->ibox, &real_flags,
-                                       flags->keywords,
-                                       flags->keywords_count))
-               return FALSE;
 
-       t_push();
-       if (!write_from_line(ctx, received_date) ||
-           !mail_storage_save(ctx->ibox->box.storage,
-                              ctx->ibox->index->mailbox_path,
-                              data, ctx->output,
-                              getenv("MAIL_SAVE_CRLF") != NULL,
-                              save_header_callback, ctx) ||
-           !mbox_fix_header(ctx) ||
-           !mbox_append_lf(ctx)) {
-               /* failed, truncate file back to original size.
-                  output stream needs to be flushed before truncating
-                  so unref() won't write anything. */
-               o_stream_flush(ctx->output);
-               if (ctx->sync_offset != (uoff_t)-1) {
-                       (void)ftruncate(ctx->ibox->index->mbox_fd,
-                                       ctx->sync_offset);
-                       ctx->sync_offset = (uoff_t)-1;
+       if (ctx == NULL) {
+               ctx = t->save_ctx = i_new(struct mbox_save_context, 1);
+               ctx->ibox = ibox;
+               ctx->append_offset = (uoff_t)-1;
+       }
+
+       if (ctx->append_offset == (uoff_t)-1) {
+               if (ibox->mbox_lock_type != F_WRLCK) {
+                       if (mbox_lock(ibox, F_WRLCK, &t->mbox_lock_id) <= 0)
+                               return -1;
                }
-               failed = TRUE;
+
+               if (ibox->mbox_fd == -1) {
+                       if (mbox_file_open(ibox) < 0)
+                               return -1;
+               }
+
+               if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0)
+                       return -1;
+
+               ctx->output = o_stream_create_file(ibox->mbox_fd, default_pool,
+                                                  4096, FALSE);
+               o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
+       }
+
+       i_assert(ibox->mbox_lock_type == F_WRLCK);
+
+       t_push();
+       if (write_from_line(ctx, received_date, from_envelope) < 0 ||
+           mail_storage_save(ibox->box.storage, ibox->path, data, ctx->output,
+                             getenv("MAIL_SAVE_CRLF") != NULL,
+                             save_header_callback, ctx) < 0 ||
+           mbox_fix_header(ctx) < 0 ||
+           mbox_append_lf(ctx) < 0) {
+               ret = -1;
        } else {
-               if (!ctx->transaction)
-                       ctx->sync_offset = ctx->output->offset;
-               failed = FALSE;
+               ret = 0;
        }
        t_pop();
-
-       return !failed;
+       return ret;
 }
 
-struct mail_save_context *
-mbox_storage_save_init(struct mailbox *box, int transaction)
+static void mbox_save_deinit(struct mbox_save_context *ctx)
 {
-       struct index_mailbox *ibox = (struct index_mailbox *) box;
-       struct mail_save_context *ctx;
-
-       if (box->is_readonly(box)) {
-               mail_storage_set_error(box->storage, "Mailbox is read-only");
-               return NULL;
-       }
-
-       if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
-                                        MAIL_LOCK_EXCLUSIVE))
-               return NULL;
+       if (ctx->output != NULL)
+               o_stream_unref(ctx->output);
+       i_free(ctx);
+}
 
-       ctx = i_new(struct mail_save_context, 1);
-       ctx->ibox = ibox;
-       ctx->transaction = transaction;
+int mbox_save_commit(struct mbox_save_context *ctx)
+{
+       int ret = 0;
 
-       if (!mbox_seek_to_end(ctx, &ctx->sync_offset)) {
-               i_free(ctx);
-               return NULL;
+       if (ctx->ibox->mbox_fd != -1) {
+               if (fdatasync(ctx->ibox->mbox_fd) < 0) {
+                       mbox_set_syscall_error(ctx->ibox, "fsync()");
+                       ret = -1;
+               }
        }
 
-       ctx->output = o_stream_create_file(ibox->index->mbox_fd,
-                                          default_pool, 4096, FALSE);
-       o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
-       return ctx;
+       mbox_save_deinit(ctx);
+       return ret;
 }
 
-int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback)
+void mbox_save_rollback(struct mbox_save_context *ctx)
 {
-       int failed = FALSE;
+       struct index_mailbox *ibox = ctx->ibox;
 
-       if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK))
-               failed = TRUE;
+       if (ctx->append_offset != (uoff_t)-1 && ibox->mbox_fd != -1) {
+               i_assert(ibox->mbox_lock_type == F_WRLCK);
 
-       if (o_stream_flush(ctx->output) < 0)
-               failed = TRUE;
-       o_stream_unref(ctx->output);
+               /* failed, truncate file back to original size.
+                  output stream needs to be flushed before truncating
+                  so unref() won't write anything. */
+               o_stream_flush(ctx->output);
 
-       if (rollback && ctx->sync_offset != (uoff_t)-1) {
-               if (ftruncate(ctx->ibox->index->mbox_fd,
-                             ctx->sync_offset) < 0) {
-                       syscall_error(ctx, "ftruncate()");
-                       failed = TRUE;
-               }
-       } else {
-               if (fdatasync(ctx->ibox->index->mbox_fd) < 0) {
-                       syscall_error(ctx, "fsync()");
-                       failed = TRUE;
-               }
+               if (ftruncate(ibox->mbox_fd, (off_t)ctx->append_offset) < 0)
+                       mbox_set_syscall_error(ibox, "ftruncate()");
        }
 
-       i_free(ctx);
-       return !failed;
+       mbox_save_deinit(ctx);
 }
-#endif
index 493a00aac57f42dbb8d276543e23f7f5b42fb1fb..ca85aea8c97c9319f2b2d01b6d8dc90c7effd5a2 100644 (file)
@@ -1,14 +1,14 @@
 /* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
+#include "buffer.h"
 #include "home-expand.h"
 #include "mkdir-parents.h"
 #include "unlink-directory.h"
 #include "subscription-file/subscription-file.h"
-#include "mail-keywords.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
 #include "mbox-storage.h"
+#include "mbox-lock.h"
+#include "mail-save.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 extern struct mail_storage mbox_storage;
 extern struct mailbox mbox_mailbox;
 
-static int mbox_handle_errors(struct mail_storage *storage)
+int mbox_set_syscall_error(struct index_mailbox *ibox, const char *function)
+{
+       i_assert(function != NULL);
+
+       mail_storage_set_critical(ibox->box.storage,
+               "%s failed with mbox file %s: %m", function, ibox->path);
+       return -1;
+}
+
+static int mbox_handle_errors(struct index_storage *istorage)
 {
+       struct mail_storage *storage = &istorage->storage;
+
        if (ENOACCESS(errno))
                mail_storage_set_error(storage, "Permission denied");
        else if (ENOSPACE(errno))
@@ -130,7 +141,7 @@ static struct mail_storage *
 mbox_create(const char *data, const char *user,
            const char *namespace, char hierarchy_sep)
 {
-       struct mail_storage *storage;
+       struct index_storage *storage;
        const char *root_dir, *inbox_file, *index_dir, *p;
        struct stat st;
        int autodetect;
@@ -191,39 +202,40 @@ mbox_create(const char *data, const char *user,
        else if (strcmp(index_dir, "MEMORY") == 0)
                index_dir = NULL;
 
-       storage = i_new(struct mail_storage, 1);
-       memcpy(storage, &mbox_storage, sizeof(struct mail_storage));
+       storage = i_new(struct index_storage, 1);
+       storage->storage = mbox_storage;
 
        if (hierarchy_sep != '\0')
-               storage->hierarchy_sep = hierarchy_sep;
-       storage->namespace = i_strdup(namespace);
+               storage->storage.hierarchy_sep = hierarchy_sep;
+       storage->storage.namespace = i_strdup(namespace);
 
        storage->dir = i_strdup(home_expand(root_dir));
-       storage->inbox_file = i_strdup(home_expand(inbox_file));
+       storage->inbox_path = i_strdup(home_expand(inbox_file));
        storage->index_dir = i_strdup(home_expand(index_dir));
        storage->user = i_strdup(user);
        storage->callbacks = i_new(struct mail_storage_callbacks, 1);
        index_storage_init(storage);
-       return storage;
+       return &storage->storage;
 }
 
-static void mbox_free(struct mail_storage *storage)
+static void mbox_free(struct mail_storage *_storage)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
+
        index_storage_deinit(storage);
 
-       i_free(storage->namespace);
        i_free(storage->dir);
-       i_free(storage->inbox_file);
+       i_free(storage->inbox_path);
        i_free(storage->index_dir);
        i_free(storage->user);
-       i_free(storage->error);
        i_free(storage->callbacks);
        i_free(storage);
 }
 
-const char *mbox_fix_mailbox_name(struct mail_storage *storage,
+const char *mbox_fix_mailbox_name(struct index_storage *istorage,
                                  const char *name, int remove_namespace)
 {
+        struct mail_storage *storage = &istorage->storage;
        char *dup, *p, sep;
        size_t len;
 
@@ -304,7 +316,7 @@ static int mbox_is_valid_existing_name(const char *name)
        return mbox_is_valid_mask(name);
 }
 
-static const char *mbox_get_index_dir(struct mail_storage *storage,
+static const char *mbox_get_index_dir(struct index_storage *storage,
                                      const char *name)
 {
        const char *p;
@@ -329,56 +341,58 @@ static const char *mbox_get_index_dir(struct mail_storage *storage,
        }
 }
 
-static int create_mbox_index_dirs(struct mail_storage *storage,
+static int create_mbox_index_dirs(struct index_storage *storage,
                                  const char *name)
 {
        const char *index_dir;
 
        index_dir = mbox_get_index_dir(storage, name);
        if (index_dir == NULL)
-               return TRUE;
+               return 0;
 
        if (mkdir_parents(index_dir, CREATE_MODE) < 0) {
-               mail_storage_set_critical(storage,
+               mail_storage_set_critical(&storage->storage,
                        "mkdir_parents(%s) failed: %m", index_dir);
-               return FALSE;
+               return -1;
        }
 
-       return TRUE;
+       return 0;
 }
 
-static int verify_inbox(struct mail_storage *storage)
+static int verify_inbox(struct index_storage *storage)
 {
        int fd;
 
        /* make sure inbox file itself exists */
-       fd = open(storage->inbox_file, O_RDWR | O_CREAT | O_EXCL, 0660);
+       fd = open(storage->inbox_path, O_RDWR | O_CREAT | O_EXCL, 0660);
        if (fd != -1)
                (void)close(fd);
 
        /* make sure the index directories exist */
-       if (!create_mbox_index_dirs(storage, "INBOX"))
-               return FALSE;
+       if (create_mbox_index_dirs(storage, "INBOX") < 0)
+               return -1;
 
-       return TRUE;
+       return 0;
 }
 
-static const char *mbox_get_path(struct mail_storage *storage, const char *name)
+static const char *
+mbox_get_path(struct index_storage *storage, const char *name)
 {
        if (strcasecmp(name, "INBOX") == 0)
-               return storage->inbox_file;
+               return storage->inbox_path;
        if (full_filesystem_access && (*name == '/' || *name == '~'))
                return home_expand(name);
        return t_strconcat(storage->dir, "/", name, NULL);
 }
 
-static void mbox_mail_init(struct index_mail *mail)
+static uint32_t mbox_get_recent_count(struct index_mailbox *ibox)
 {
-       mail->mail.expunge = mbox_storage_expunge;
+       return 0; // FIXME
 }
 
-static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
-                                enum mailbox_open_flags flags)
+static struct mailbox *
+mbox_open(struct index_storage *storage, const char *name,
+         enum mailbox_open_flags flags)
 {
        struct index_mailbox *ibox;
        struct mail_index *index;
@@ -388,7 +402,7 @@ static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
                /* name = "INBOX"
                   path = "<inbox_file>/INBOX"
                   index_dir = "/mail/.imap/INBOX" */
-               path = storage->inbox_file;
+               path = storage->inbox_path;
                index_dir = mbox_get_index_dir(storage, "INBOX");
        } else {
                /* name = "foo/bar"
@@ -398,99 +412,105 @@ static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
                index_dir = mbox_get_index_dir(storage, name);
        }
 
-       index = index_storage_lookup_ref(index_dir, path);
-       if (index == NULL) {
-               index = mbox_index_alloc(path, index_dir, index_dir);
-               index_storage_add(index);
-       }
+       index = index_storage_alloc(index_dir, path, MBOX_INDEX_PREFIX);
+       ibox = index_storage_mailbox_init(storage, &mbox_mailbox,
+                                         index, name, flags);
+       if (ibox == NULL)
+               return NULL;
+
+       ibox->path = i_strdup(path);
+       ibox->mbox_fd = -1;
 
-       ibox = index_storage_mailbox_init(storage, &mbox_mailbox, index,
-                                         name, flags);
-       if (ibox != NULL)
-               ibox->mail_init = mbox_mail_init;
-       return (struct mailbox *) ibox;
+       ibox->get_recent_count = mbox_get_recent_count;
+       ibox->mail_interface = &mbox_mail;
+
+       return &ibox->box;
 }
 
 static struct mailbox *
-mbox_open_mailbox(struct mail_storage *storage,
+mbox_mailbox_open(struct mail_storage *_storage,
                  const char *name, enum mailbox_open_flags flags)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
        const char *path;
        struct stat st;
 
-       mail_storage_clear_error(storage);
+       mail_storage_clear_error(_storage);
 
        name = mbox_fix_mailbox_name(storage, name, TRUE);
 
        /* INBOX is always case-insensitive */
        if (strcasecmp(name, "INBOX") == 0) {
                /* make sure inbox exists */
-               if (!verify_inbox(storage))
-                       return FALSE;
+               if (verify_inbox(storage) < 0)
+                       return NULL;
                return mbox_open(storage, "INBOX", flags);
        }
 
        if (!mbox_is_valid_existing_name(name)) {
-               mail_storage_set_error(storage, "Invalid mailbox name");
-               return FALSE;
+               mail_storage_set_error(_storage, "Invalid mailbox name");
+               return NULL;
        }
 
        path = mbox_get_path(storage, name);
        if (stat(path, &st) == 0) {
                if (S_ISDIR(st.st_mode)) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Mailbox isn't selectable: %s", name);
                        return NULL;
                }
 
                /* exists - make sure the required directories are also there */
-               if (!create_mbox_index_dirs(storage, name))
+               if (create_mbox_index_dirs(storage, name) < 0)
                        return NULL;
 
                return mbox_open(storage, name, flags);
        }
 
        if (ENOTFOUND(errno)) {
-               mail_storage_set_error(storage, "Mailbox doesn't exist: %s",
+               mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
                                       name);
-       } else if (!mbox_handle_errors(storage))
-               mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
+       } else if (!mbox_handle_errors(storage)) {
+               mail_storage_set_critical(_storage, "stat(%s) failed: %m",
+                                         path);
+       }
 
        return NULL;
 }
 
-static int mbox_create_mailbox(struct mail_storage *storage, const char *name,
+static int mbox_mailbox_create(struct mail_storage *_storage, const char *name,
                               int directory)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
        const char *path, *p;
        struct stat st;
        int fd;
 
-       mail_storage_clear_error(storage);
+       mail_storage_clear_error(_storage);
 
        name = mbox_fix_mailbox_name(storage, name, TRUE);
 
        if (!mbox_is_valid_create_name(name)) {
-               mail_storage_set_error(storage, "Invalid mailbox name");
-               return FALSE;
+               mail_storage_set_error(_storage, "Invalid mailbox name");
+               return -1;
        }
 
        /* make sure it doesn't exist already */
        path = mbox_get_path(storage, name);
        if (stat(path, &st) == 0) {
-               mail_storage_set_error(storage, "Mailbox already exists");
-               return FALSE;
+               mail_storage_set_error(_storage, "Mailbox already exists");
+               return -1;
        }
 
        if (errno != ENOENT && errno != ELOOP && errno != EACCES) {
                if (errno == ENOTDIR) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Mailbox doesn't allow inferior mailboxes");
                } else {
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "stat() failed for mbox file %s: %m", path);
                }
-               return FALSE;
+               return -1;
        }
 
        /* create the hierarchy if needed */
@@ -499,16 +519,16 @@ static int mbox_create_mailbox(struct mail_storage *storage, const char *name,
                p = t_strdup_until(path, p);
                if (mkdir_parents(p, CREATE_MODE) < 0) {
                        if (mbox_handle_errors(storage))
-                               return FALSE;
+                               return -1;
 
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "mkdir_parents(%s) failed: %m", p);
-                       return FALSE;
+                       return -1;
                }
 
                if (directory) {
                        /* wanted to create only the directory */
-                       return TRUE;
+                       return 0;
                }
        }
 
@@ -516,48 +536,49 @@ static int mbox_create_mailbox(struct mail_storage *storage, const char *name,
        fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
        if (fd != -1) {
                (void)close(fd);
-               return TRUE;
+               return 0;
        }
 
        if (errno == EEXIST) {
                /* mailbox was just created between stat() and open() call.. */
-               mail_storage_set_error(storage, "Mailbox already exists");
+               mail_storage_set_error(_storage, "Mailbox already exists");
        } else if (!mbox_handle_errors(storage)) {
-               mail_storage_set_critical(storage,
+               mail_storage_set_critical(_storage,
                        "Can't create mailbox %s: %m", name);
        }
-       return FALSE;
+       return -1;
 }
 
-static int mbox_delete_mailbox(struct mail_storage *storage, const char *name)
+static int mbox_mailbox_delete(struct mail_storage *_storage, const char *name)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
        const char *index_dir, *path;
        struct stat st;
 
-       mail_storage_clear_error(storage);
+       mail_storage_clear_error(_storage);
 
        name = mbox_fix_mailbox_name(storage, name, TRUE);
 
        if (strcasecmp(name, "INBOX") == 0) {
-               mail_storage_set_error(storage, "INBOX can't be deleted.");
-               return FALSE;
+               mail_storage_set_error(_storage, "INBOX can't be deleted.");
+               return -1;
        }
 
        if (!mbox_is_valid_existing_name(name)) {
-               mail_storage_set_error(storage, "Invalid mailbox name");
-               return FALSE;
+               mail_storage_set_error(_storage, "Invalid mailbox name");
+               return -1;
        }
 
        path = mbox_get_path(storage, name);
        if (lstat(path, &st) < 0) {
                if (ENOTFOUND(errno)) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Mailbox doesn't exist: %s", name);
                } else if (!mbox_handle_errors(storage)) {
-                       mail_storage_set_critical(storage, "lstat() failed for "
-                                                 "%s: %m", path);
+                       mail_storage_set_critical(_storage,
+                               "lstat() failed for %s: %m", path);
                }
-               return FALSE;
+               return -1;
        }
 
        if (S_ISDIR(st.st_mode)) {
@@ -568,40 +589,40 @@ static int mbox_delete_mailbox(struct mail_storage *storage, const char *name)
 
                if (index_dir != NULL && rmdir(index_dir) < 0 &&
                    !ENOTFOUND(errno) && errno != ENOTEMPTY) {
-                       if (!mbox_handle_errors(storage)) {
-                               mail_storage_set_critical(storage,
+                       if (!mbox_handle_errors(storage) < 0) {
+                               mail_storage_set_critical(_storage,
                                        "rmdir() failed for %s: %m", index_dir);
-                               return FALSE;
+                               return -1;
                        }
                }
 
                if (rmdir(path) == 0)
-                       return TRUE;
+                       return 0;
 
                if (ENOTFOUND(errno)) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Mailbox doesn't exist: %s", name);
                } else if (errno == ENOTEMPTY) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Folder %s isn't empty, can't delete it.",
                                name);
                } else if (!mbox_handle_errors(storage)) {
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "rmdir() failed for %s: %m", path);
                }
-               return FALSE;
+               return -1;
        }
 
        /* first unlink the mbox file */
        if (unlink(path) < 0) {
                if (ENOTFOUND(errno)) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Mailbox doesn't exist: %s", name);
                } else if (!mbox_handle_errors(storage)) {
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "unlink() failed for %s: %m", path);
                }
-               return FALSE;
+               return -1;
        }
 
        /* next delete the index directory */
@@ -610,7 +631,7 @@ static int mbox_delete_mailbox(struct mail_storage *storage, const char *name)
                index_storage_destroy_unrefed();
 
                if (unlink_directory(index_dir, TRUE) < 0 && errno != ENOENT) {
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "unlink_directory(%s) failed: %m", index_dir);
 
                        /* mailbox itself is deleted, so return success
@@ -618,24 +639,25 @@ static int mbox_delete_mailbox(struct mail_storage *storage, const char *name)
                }
        }
 
-       return TRUE;
+       return 0;
 }
 
-static int mbox_rename_mailbox(struct mail_storage *storage,
+static int mbox_mailbox_rename(struct mail_storage *_storage,
                               const char *oldname, const char *newname)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
        const char *oldpath, *newpath, *old_indexdir, *new_indexdir, *p;
        struct stat st;
 
-       mail_storage_clear_error(storage);
+       mail_storage_clear_error(_storage);
 
        oldname = mbox_fix_mailbox_name(storage, oldname, TRUE);
        newname = mbox_fix_mailbox_name(storage, newname, TRUE);
 
        if (!mbox_is_valid_existing_name(oldname) ||
            !mbox_is_valid_create_name(newname)) {
-               mail_storage_set_error(storage, "Invalid mailbox name");
-               return FALSE;
+               mail_storage_set_error(_storage, "Invalid mailbox name");
+               return -1;
        }
 
        oldpath = mbox_get_path(storage, oldname);
@@ -647,11 +669,11 @@ static int mbox_rename_mailbox(struct mail_storage *storage,
                p = t_strdup_until(newpath, p);
                if (mkdir_parents(p, CREATE_MODE) < 0) {
                        if (mbox_handle_errors(storage))
-                               return FALSE;
+                               return -1;
 
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "mkdir_parents(%s) failed: %m", p);
-                       return FALSE;
+                       return -1;
                }
        }
 
@@ -660,26 +682,26 @@ static int mbox_rename_mailbox(struct mail_storage *storage,
           possibility that someone actually tries to rename two mailboxes
           to same new one */
        if (lstat(newpath, &st) == 0) {
-               mail_storage_set_error(storage,
+               mail_storage_set_error(_storage,
                                       "Target mailbox already exists");
-               return FALSE;
+               return -1;
        } else if (!ENOTFOUND(errno) && errno != EACCES) {
-               mail_storage_set_critical(storage, "lstat(%s) failed: %m",
+               mail_storage_set_critical(_storage, "lstat(%s) failed: %m",
                                          newpath);
-               return FALSE;
+               return -1;
        }
 
        /* NOTE: renaming INBOX works just fine with us, it's simply recreated
           the next time it's needed. */
        if (rename(oldpath, newpath) < 0) {
                if (ENOTFOUND(errno)) {
-                       mail_storage_set_error(storage,
+                       mail_storage_set_error(_storage,
                                "Mailbox doesn't exist: %s", oldname);
                } else if (!mbox_handle_errors(storage)) {
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                "rename(%s, %s) failed: %m", oldpath, newpath);
                }
-               return FALSE;
+               return -1;
        }
 
        /* we need to rename the index directory as well */
@@ -688,85 +710,82 @@ static int mbox_rename_mailbox(struct mail_storage *storage,
        if (old_indexdir != NULL) {
                if (rename(old_indexdir, new_indexdir) < 0 &&
                    errno != ENOENT) {
-                       mail_storage_set_critical(storage,
+                       mail_storage_set_critical(_storage,
                                                  "rename(%s, %s) failed: %m",
                                                  old_indexdir, new_indexdir);
                }
        }
 
-       return TRUE;
+       return 0;
 }
 
-static int mbox_set_subscribed(struct mail_storage *storage,
+static int mbox_set_subscribed(struct mail_storage *_storage,
                               const char *name, int set)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
+       const char *path;
+
+       path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL);
        name = mbox_fix_mailbox_name(storage, name, FALSE);
-       return subsfile_set_subscribed(storage, name, set);
+       return subsfile_set_subscribed(_storage, path, name, set);
 }
 
-static int mbox_get_mailbox_name_status(struct mail_storage *storage,
+static int mbox_get_mailbox_name_status(struct mail_storage *_storage,
                                        const char *name,
                                        enum mailbox_name_status *status)
 {
+       struct index_storage *storage = (struct index_storage *)_storage;
        struct stat st;
        const char *path;
 
-       mail_storage_clear_error(storage);
+       mail_storage_clear_error(_storage);
 
        name = mbox_fix_mailbox_name(storage, name, TRUE);
 
        if (!mbox_is_valid_existing_name(name)) {
                *status = MAILBOX_NAME_INVALID;
-               return TRUE;
+               return 0;
        }
 
        path = mbox_get_path(storage, name);
        if (stat(path, &st) == 0) {
                *status = MAILBOX_NAME_EXISTS;
-               return TRUE;
+               return 0;
        }
 
        if (!mbox_is_valid_create_name(name)) {
                *status = MAILBOX_NAME_INVALID;
-               return TRUE;
+               return 0;
        }
 
        if (ENOTFOUND(errno) || errno == EACCES) {
                *status = MAILBOX_NAME_VALID;
-               return TRUE;
+               return 0;
        } else if (errno == ENOTDIR) {
                *status = MAILBOX_NAME_NOINFERIORS;
-               return TRUE;
+               return 0;
        } else {
-               mail_storage_set_critical(storage, "mailbox name status: "
+               mail_storage_set_critical(_storage, "mailbox name status: "
                                          "stat(%s) failed: %m", path);
-               return FALSE;
+               return -1;
        }
 }
 
 static int mbox_storage_close(struct mailbox *box)
 {
-       struct index_mailbox *ibox = (struct index_mailbox *) box;
-       int failed = FALSE;
-
-       /* update flags by rewrite mbox file */
-        index_storage_init_lock_notify(ibox);
-       if (!ibox->index->mailbox_readonly) {
-               if (!mbox_index_rewrite(ibox->index)) {
-                       mail_storage_set_index_error(ibox);
-                       failed = TRUE;
-               }
-       }
-       ibox->index->set_lock_notify_callback(ibox->index, NULL, NULL);
+       struct index_mailbox *ibox = (struct index_mailbox *)box;
 
-       return index_storage_mailbox_free(box) && !failed;
+       if (ibox->mbox_data_buf != NULL)
+               buffer_free(ibox->mbox_data_buf);
+        index_storage_mailbox_free(box);
+       return 0;
 }
 
 static void mbox_storage_auto_sync(struct mailbox *box,
                                   enum mailbox_sync_flags flags,
                                   unsigned int min_newmail_notify_interval)
 {
-       struct index_mailbox *ibox = (struct index_mailbox *) box;
+       struct index_mailbox *ibox = (struct index_mailbox *)box;
 
        ibox->min_newmail_notify_interval = min_newmail_notify_interval;
 
@@ -780,40 +799,7 @@ static void mbox_storage_auto_sync(struct mailbox *box,
        if (flags == 0)
                index_mailbox_check_remove_all(ibox);
        else
-               index_mailbox_check_add(ibox, ibox->index->mailbox_path, FALSE);
-}
-
-static int mbox_storage_lock(struct mailbox *box,
-                            enum mailbox_lock_type lock_type)
-{
-       struct index_mailbox *ibox = (struct index_mailbox *) box;
-
-       if (lock_type == MAIL_LOCK_UNLOCK) {
-               ibox->lock_type = MAIL_LOCK_UNLOCK;
-               if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK))
-                       return FALSE;
-               return TRUE;
-       }
-
-       i_assert(ibox->lock_type == MAIL_LOCK_UNLOCK);
-
-       if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_FLAGS)) != 0) {
-               if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
-                       return FALSE;
-       } else if ((lock_type & MAILBOX_LOCK_READ) != 0) {
-               if (!index_storage_lock(ibox, MAIL_LOCK_SHARED))
-                       return FALSE;
-       }
-
-       if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_SAVE)) != 0) {
-               /* FIXME: saving doesn't have to sync it, just lock it */
-               if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
-                                                MAIL_LOCK_EXCLUSIVE))
-                       return FALSE;
-       }
-
-       ibox->lock_type = lock_type;
-       return TRUE;
+               index_mailbox_check_add(ibox, ibox->path, FALSE);
 }
 
 struct mail_storage mbox_storage = {
@@ -826,24 +812,18 @@ struct mail_storage mbox_storage = {
        mbox_free,
        mbox_autodetect,
        index_storage_set_callbacks,
-       mbox_open_mailbox,
-       mbox_create_mailbox,
-       mbox_delete_mailbox,
-       mbox_rename_mailbox,
-       mbox_list_mailbox_init,
-       mbox_list_mailbox_deinit,
-       mbox_list_mailbox_next,
+       mbox_mailbox_open,
+       mbox_mailbox_create,
+       mbox_mailbox_delete,
+       mbox_mailbox_rename,
+       mbox_mailbox_list_init,
+       mbox_mailbox_list_next,
+       mbox_mailbox_list_deinit,
        mbox_set_subscribed,
        mbox_get_mailbox_name_status,
        mail_storage_get_last_error,
 
        NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL, NULL, NULL,
-
        0
 };
 
@@ -854,24 +834,19 @@ struct mailbox mbox_mailbox = {
        index_storage_is_readonly,
         index_storage_allow_new_keywords,
        mbox_storage_close,
-       mbox_storage_lock,
        index_storage_get_status,
-       index_storage_sync,
+       mbox_storage_sync,
        mbox_storage_auto_sync,
-       index_storage_fetch_uid,
-       index_storage_fetch_seq,
+       mbox_transaction_begin,
+       mbox_transaction_commit,
+       mbox_transaction_rollback,
+       index_storage_fetch,
+       index_storage_get_uids,
         index_storage_search_get_sorting,
        index_storage_search_init,
        index_storage_search_deinit,
        index_storage_search_next,
-       mbox_storage_save_init,
-       mbox_storage_save_deinit,
-       mbox_storage_save_next,
-       index_storage_copy_init,
-       index_storage_copy_deinit,
-       index_storage_copy,
-       mbox_storage_expunge_init,
-       mbox_storage_expunge_deinit,
-       mbox_storage_expunge_fetch_next,
-       index_storage_is_inconsistency_error
+       mbox_save,
+       mail_storage_copy,
+       index_storage_is_inconsistent
 };
index 3912c1c5858e21b709808618befc8efdf88187b1..73e5e81636d0875477a13c7054142ddc7319c3d4 100644 (file)
@@ -1,34 +1,46 @@
 #ifndef __MBOX_STORAGE_H
 #define __MBOX_STORAGE_H
 
+/* Extra space to leave in X-Keywords header when rewriting mbox */
+#define MBOX_HEADER_EXTRA_SPACE 100
+
+#define SUBSCRIPTION_FILE_NAME "subscriptions"
+#define MBOX_INDEX_PREFIX "dovecot.index"
+
 #include "index-storage.h"
 
-int mbox_storage_copy(struct mailbox *box, struct mailbox *destbox,
-                     const char *messageset, int uidset);
+struct mbox_transaction_context {
+       struct index_transaction_context ictx;
+
+       struct mbox_save_context *save_ctx;
+       unsigned int mbox_lock_id;
+};
+
+extern struct mail mbox_mail;
 
-struct mail_save_context *
-mbox_storage_save_init(struct mailbox *box, int transaction);
-int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback);
-int mbox_storage_save_next(struct mail_save_context *ctx,
-                          const struct mail_full_flags *flags,
-                          time_t received_date, int timezone_offset,
-                          struct istream *data);
+int mbox_set_syscall_error(struct index_mailbox *ibox, const char *function);
 
 struct mailbox_list_context *
-mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
+mbox_mailbox_list_init(struct mail_storage *storage, const char *mask,
                       enum mailbox_list_flags flags);
-int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx);
-struct mailbox_list *mbox_list_mailbox_next(struct mailbox_list_context *ctx);
-
-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);
-
-const char *mbox_fix_mailbox_name(struct mail_storage *storage,
+int mbox_mailbox_list_deinit(struct mailbox_list_context *ctx);
+struct mailbox_list *mbox_mailbox_list_next(struct mailbox_list_context *ctx);
+
+struct mailbox_transaction_context *
+mbox_transaction_begin(struct mailbox *box, int hide);
+int mbox_transaction_commit(struct mailbox_transaction_context *t);
+void mbox_transaction_rollback(struct mailbox_transaction_context *t);
+
+int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+
+int mbox_save(struct mailbox_transaction_context *t,
+             const struct mail_full_flags *flags,
+             time_t received_date, int timezone_offset,
+             const char *from_envelope, struct istream *data);
+int mbox_save_commit(struct mbox_save_context *ctx);
+void mbox_save_rollback(struct mbox_save_context *ctx);
+
+const char *mbox_fix_mailbox_name(struct index_storage *istorage,
                                  const char *name, int remove_namespace);
 int mbox_is_valid_mask(const char *mask);
 
index f2005e716eec63c98d909c9a80772cc8d32adaa3..70a2db6acfb2f1c692f95b95a93d19e1f6e55656 100644 (file)
@@ -85,27 +85,24 @@ static int parse_x_imap_base(struct mbox_sync_mail_context *ctx,
                return FALSE;
        }
 
-       t_push();
-
        /* <uid validity> <last uid> */
+       t_push();
        str = t_strndup(hdr->full_value, hdr->full_value_len);
        ctx->base_uid_validity = strtoul(str, &end, 10);
        ctx->base_uid_last = strtoul(end, &end, 10);
        pos = end - str;
+       t_pop();
 
        while (pos < hdr->full_value_len && IS_LWSP_LF(hdr->full_value[pos]))
                pos++;
 
        if (ctx->base_uid_validity == 0) {
                /* broken */
-               t_pop();
                return FALSE;
        }
 
-       if (pos == hdr->full_value_len) {
-               t_pop();
+       if (pos == hdr->full_value_len)
                return TRUE;
-       }
 
        // FIXME: save keywords
 
index 1de069e92380a152a40bacf9b6d6e3d6f578a573..f1e797d47a7c56b60815969fdfa70e01b8fd1ab5 100644 (file)
@@ -25,7 +25,7 @@ enum header_position {
 extern struct mbox_flag_type mbox_status_flags[];
 extern struct mbox_flag_type mbox_xstatus_flags[];
 
-struct mbox_mail {
+struct mbox_sync_mail {
        uint32_t uid;
        uint8_t flags;
        keywords_mask_t keywords;
@@ -37,7 +37,7 @@ struct mbox_mail {
 
 struct mbox_sync_mail_context {
        struct mbox_sync_context *sync_ctx;
-       struct mbox_mail *mail;
+       struct mbox_sync_mail *mail;
 
        uint32_t seq;
        uoff_t hdr_offset, body_offset;
@@ -55,8 +55,8 @@ struct mbox_sync_mail_context {
 };
 
 struct mbox_sync_context {
-       struct istream *file_input;
-       struct istream *input;
+       struct index_mailbox *ibox;
+       struct istream *input, *file_input;
        int fd;
 
        const struct mail_index_header *hdr;
@@ -64,6 +64,7 @@ struct mbox_sync_context {
        uint32_t prev_msg_uid, next_uid;
 };
 
+int mbox_sync(struct index_mailbox *ibox, int last_commit);
 void mbox_sync_parse_next_mail(struct istream *input,
                               struct mbox_sync_mail_context *ctx);
 void mbox_sync_update_header(struct mbox_sync_mail_context *ctx,
index 8ce28ab8bd537cccec697a0ff4de17053628ab95..175854e85bfdf41e4f693f594ff61d39ecd7f261 100644 (file)
@@ -19,7 +19,7 @@ int mbox_move(struct mbox_sync_context *sync_ctx,
        i_stream_seek(sync_ctx->file_input, source);
        o_stream_seek(output, dest);
 
-       istream_raw_mbox_flush(sync_ctx->input);
+       istream_raw_mbox_flush(sync_ctx->file_input);
 
        if (size == (uoff_t)-1) {
                input = sync_ctx->file_input;
@@ -157,7 +157,7 @@ int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx)
 int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, buffer_t *mails_buf,
                      uint32_t first_seq, uint32_t last_seq, off_t extra_space)
 {
-       struct mbox_mail *mails;
+       struct mbox_sync_mail *mails;
        size_t size;
        uint32_t first_idx, last_idx, extra_per_mail;
 
index 090532b25ebaaa8a4a8bc180d58880fc48223b0e..fa5850ac06234b761a80046a7555101eb765a44d 100644 (file)
 */
 
 #include "lib.h"
+#include "ioloop.h"
 #include "buffer.h"
 #include "istream.h"
 #include "file-set-size.h"
 #include "str.h"
 #include "write-full.h"
 #include "istream-raw-mbox.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
 #include "mbox-sync-private.h"
 
+#include <sys/stat.h>
+
 static int mbox_sync_grow_file(struct mbox_sync_context *sync_ctx,
-                              struct mbox_mail *mail, uoff_t body_offset,
+                              struct mbox_sync_mail *mail, uoff_t body_offset,
                               uoff_t grow_size)
 {
        char spaces[1024];
@@ -112,41 +117,94 @@ static int mbox_sync_grow_file(struct mbox_sync_context *sync_ctx,
        return 0;
 }
 
-int mbox_sync(struct istream *input)
+int mbox_sync(struct index_mailbox *ibox, int last_commit)
 {
        struct mbox_sync_context sync_ctx;
        struct mbox_sync_mail_context mail_ctx;
-       struct mbox_mail mail;
+       struct mbox_sync_mail mail;
+       struct mail_index_sync_ctx *index_sync_ctx;
+       struct mail_index_view *sync_view;
+       const struct mail_index_header *hdr;
+       struct istream *input;
        uint32_t seq, need_space_seq;
        off_t space_diff;
+       uoff_t from_offset, offset;
        buffer_t *mails;
-       int ret = 0;
+       string_t *header;
+       struct stat st;
+       int readonly, ret = 0;
+
+       if (last_commit) {
+               seq = ibox->commit_log_file_seq;
+               offset = ibox->commit_log_file_offset;
+       } else {
+               seq = 0;
+               offset = 0;
+       }
+
+       ret = mail_index_sync_begin(ibox->index, &index_sync_ctx, &sync_view,
+                                   seq, offset);
+       if (ret <= 0)
+               return ret;
+
+       if (mbox_file_open_stream(ibox) < 0)
+               return -1;
+
+       if (mail_index_get_header(sync_view, &hdr) < 0)
+               return -1;
+
+       if (ibox->mbox_data_buf == NULL) {
+               ibox->mbox_data_buf =
+                       buffer_create_dynamic(default_pool, 512, (size_t)-1);
+       } else {
+               buffer_set_used_size(ibox->mbox_data_buf, 0);
+       }
+
+       readonly = TRUE; // FIXME
+
+       // FIXME: lock the file
 
        mails = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
 
        memset(&sync_ctx, 0, sizeof(sync_ctx));
-       sync_ctx.file_input = input;
-       sync_ctx.input = i_stream_create_raw_mbox(default_pool, input);
-       sync_ctx.fd = i_stream_get_fd(input);
-       //sync_ctx.hdr = ;
+       sync_ctx.file_input = ibox->mbox_file_stream;
+       sync_ctx.input = ibox->mbox_stream;
+       sync_ctx.fd = ibox->mbox_fd;
+       sync_ctx.hdr = hdr;
 
        input = sync_ctx.input;
+       header = str_new(default_pool, 4096);
 
        space_diff = 0; need_space_seq = 0; seq = 1;
        for (seq = 1; !input->eof; seq++) {
+               from_offset = input->v_offset;
+
                memset(&mail, 0, sizeof(mail));
                memset(&mail_ctx, 0, sizeof(mail_ctx));
                mail_ctx.sync_ctx = &sync_ctx;
                mail_ctx.mail = &mail;
                mail_ctx.seq = seq;
+               mail_ctx.header = header;
 
                mbox_sync_parse_next_mail(input, &mail_ctx);
+               if (input->v_offset == from_offset) {
+                       /* this was the last mail */
+                       break;
+               }
+
                mail.body_size =
                        istream_raw_mbox_get_size(input,
                                                  mail_ctx.content_length);
                buffer_append(mails, &mail, sizeof(mail));
 
-               if (mail_ctx.need_rewrite) {
+               /* save the offset permanently with recent flag state */
+               from_offset <<= 1;
+               if ((mail.flags & MBOX_NONRECENT) != 0)
+                       from_offset |= 1;
+               buffer_append(ibox->mbox_data_buf,
+                             &from_offset, sizeof(from_offset));
+
+               if (mail_ctx.need_rewrite && !readonly) {
                        mbox_sync_update_header(&mail_ctx, NULL);
                        if ((ret = mbox_sync_try_rewrite(&mail_ctx)) < 0)
                                break;
@@ -185,83 +243,34 @@ int mbox_sync(struct istream *input)
                        ret = -1;
        }
 
-       i_stream_unref(input);
-       return ret < 0 ? -1 : 0;
-}
-
-#if 0
-int mbox_sync(void)
-{
-       struct mail_index_view *sync_view;
-       struct mail_index_sync_ctx *sync_ctx;
-       struct mail_index_sync_rec sync_rec;
-       struct mbox_sync_context ctx;
-       struct mbox_sync_mail_context mail_ctx;
-       struct mbox_mail mail;
-       string_t *header;
-       uint32_t seq;
-       unsigned int need_space_seq;
-       uoff_t missing_space;
-       buffer_t *mails;
-       int ret;
-
-       memset(&ctx, 0, sizeof(ctx));
-       /*ctx.index = storage->index;
-       ctx.input = storage->input;*/
-       ctx.fd = i_stream_get_fd(ctx.input);
-
-       header = str_new(default_pool, 4096);
-
-       if (mail_index_sync_begin(ctx.index, &sync_ctx, &sync_view, 0, 0) < 0)
-               return -1;
-
-       ctx.hdr = mail_index_get_header(sync_view);
-       ctx.next_uid = ctx.hdr->next_uid;
-
-       seq = 1;
-       while ((ret = mail_index_sync_next(sync_ctx, &sync_rec)) > 0) {
-               while (seq < sync_rec.seq1) {
-                       seq++;
-               }
-               switch (sync_rec.type) {
-               case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
-                       break;
-               case MAIL_INDEX_SYNC_TYPE_FLAGS:
-                       break;
-               }
+       if (fstat(ibox->mbox_fd, &st) < 0) {
+               mbox_set_syscall_error(ibox, "fstat()");
+               ret = -1;
        }
 
-       while (!ctx.input->eof) {
-               memset(&mail_ctx, 0, sizeof(mail_ctx));
-               mail_ctx.parent = &ctx;
-               mail_ctx.header = header;
-               mail_ctx.seq = seq;
+       if (ret < 0) {
+               st.st_mtime = 0;
+               st.st_size = 0;
+       }
 
-               mail_ctx.hdr_offset = ctx.input->v_offset;
-               mbox_sync_mail_parse_headers(&mail_ctx);
-               mail_ctx.body_offset = ctx.input->v_offset;
-               mail_ctx.body_size =
-                       istream_raw_mbox_get_size(ctx.input,
-                                                 mail_ctx.content_length);
+       if (mail_index_sync_end(index_sync_ctx, st.st_mtime, st.st_size) < 0)
+               ret = -1;
 
-                mbox_sync_mail_add_missing_headers(&mail_ctx);
+       str_free(header);
+       return ret < 0 ? -1 : 0;
+}
 
-               ret = mbox_sync_try_rewrite_headers(&mail_ctx, &missing_space);
-               if (ret < 0)
-                       break;
-               if (missing_space != 0) {
-                       ctx.space_diff -= missing_space;
-               } else {
-                       ctx.space_diff += mail_ctx.extra_space;
-               }
+int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+{
+       struct index_mailbox *ibox = (struct index_mailbox *)box;
 
-               if (ctx.first_spacy_msg_offset == 0)
-                        ctx.first_spacy_msg_offset = mail_ctx.hdr_offset;
+       if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
+           ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
+               ibox->sync_last_check = ioloop_time;
 
-               ctx.prev_msg_uid = mail_ctx.uid;
-               istream_raw_mbox_next(ctx.input, mail_ctx.content_length);
+               if (mbox_sync(ibox, FALSE) < 0)
+                       return -1;
        }
-       str_free(header);
-       return 0;
+
+       return index_storage_sync(box, flags);
 }
-#endif
diff --git a/src/lib-storage/index/mbox/mbox-transaction.c b/src/lib-storage/index/mbox/mbox-transaction.c
new file mode 100644 (file)
index 0000000..d6ffebb
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) 2004 Timo Sirainen */
+
+#include "lib.h"
+#include "mbox-storage.h"
+#include "mbox-lock.h"
+#include "mbox-sync-private.h"
+
+struct mailbox_transaction_context *
+mbox_transaction_begin(struct mailbox *box, int hide)
+{
+       struct index_mailbox *ibox = (struct index_mailbox *)box;
+       struct mbox_transaction_context *t;
+
+       t = i_new(struct mbox_transaction_context, 1);
+       t->ictx.mailbox_ctx.box = box;
+       t->ictx.ibox = ibox;
+       t->ictx.trans = mail_index_transaction_begin(ibox->view, hide);
+       return &t->ictx.mailbox_ctx;
+}
+
+int mbox_transaction_commit(struct mailbox_transaction_context *_t)
+{
+       struct mbox_transaction_context *t =
+               (struct mbox_transaction_context *)_t;
+       struct index_mailbox *ibox = t->ictx.ibox;
+       unsigned int lock_id = t->mbox_lock_id;
+       int ret = 0;
+
+       if (t->save_ctx != NULL)
+               ret = mbox_save_commit(t->save_ctx);
+
+       if (ret == 0) {
+               if (index_transaction_commit(_t) < 0)
+                       ret = -1;
+       } else {
+               index_transaction_rollback(_t);
+       }
+
+       if (ret == 0) {
+               if (mbox_sync(ibox, TRUE) < 0)
+                       ret = -1;
+       }
+
+       if (lock_id != 0) {
+               if (mbox_unlock(ibox, lock_id) < 0)
+                       ret = -1;
+       }
+       return ret;
+}
+
+void mbox_transaction_rollback(struct mailbox_transaction_context *_t)
+{
+       struct mbox_transaction_context *t =
+               (struct mbox_transaction_context *)_t;
+       struct index_mailbox *ibox = t->ictx.ibox;
+
+       if (t->save_ctx != NULL)
+               mbox_save_rollback(t->save_ctx);
+
+       if (t->mbox_lock_id != 0)
+               (void)mbox_unlock(ibox, t->mbox_lock_id);
+       index_transaction_rollback(_t);
+}