Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1978:6303ef092c5b HEAD
mbox code compiles again, but syncing is only partially implemented so
accessing mboxes fails..
Also some cleanups to index-storage and maildir code.
line wrap: on
line diff
--- a/configure.in Tue May 04 21:13:10 2004 +0300 +++ b/configure.in Thu May 06 04:22:25 2004 +0300 @@ -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 @@ 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
--- a/src/lib-storage/index/index-mail.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/index-mail.c Thu May 06 04:22:25 2004 +0300 @@ -200,6 +200,21 @@ 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;
--- a/src/lib-storage/index/index-mail.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/index-mail.h Thu May 06 04:22:25 2004 +0300 @@ -94,6 +94,7 @@ 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,
--- a/src/lib-storage/index/index-storage.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/index-storage.c Thu May 06 04:22:25 2004 +0300 @@ -39,8 +39,11 @@ 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 @@ 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 @@ } } -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;
--- a/src/lib-storage/index/index-storage.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/index-storage.h Thu May 06 04:22:25 2004 +0300 @@ -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 @@ 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 @@ }; 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,
--- a/src/lib-storage/index/maildir/maildir-list.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-list.c Thu May 06 04:22:25 2004 +0300 @@ -19,7 +19,6 @@ 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 @@ 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 @@ } 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_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 @@ 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 @@ 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 @@ 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 @@ 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);
--- a/src/lib-storage/index/maildir/maildir-mail.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-mail.c Thu May 06 04:22:25 2004 +0300 @@ -68,9 +68,8 @@ { 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 @@ 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);
--- a/src/lib-storage/index/maildir/maildir-storage.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-storage.c Thu May 06 04:22:25 2004 +0300 @@ -108,9 +108,6 @@ 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);
--- a/src/lib-storage/index/maildir/maildir-storage.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-storage.h Thu May 06 04:22:25 2004 +0300 @@ -57,9 +57,6 @@ 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);
--- a/src/lib-storage/index/maildir/maildir-sync.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-sync.c Thu May 06 04:22:25 2004 +0300 @@ -390,6 +390,13 @@ 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);
--- a/src/lib-storage/index/maildir/maildir-uidlist.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-uidlist.c Thu May 06 04:22:25 2004 +0300 @@ -58,6 +58,7 @@ unsigned int partial:1; unsigned int synced:1; + unsigned int locked:1; unsigned int failed:1; }; @@ -559,8 +560,10 @@ /* 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 @@ { 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 @@ 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 @@ 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 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 @@ 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))
--- a/src/lib-storage/index/maildir/maildir-uidlist.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/maildir/maildir-uidlist.h Thu May 06 04:22:25 2004 +0300 @@ -31,6 +31,9 @@ /* 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);
--- a/src/lib-storage/index/mbox/Makefile.am Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/Makefile.am Thu May 06 04:22:25 2004 +0300 @@ -11,18 +11,23 @@ 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
--- a/src/lib-storage/index/mbox/istream-raw-mbox.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/istream-raw-mbox.c Thu May 06 04:22:25 2004 +0300 @@ -10,7 +10,9 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 =
--- a/src/lib-storage/index/mbox/istream-raw-mbox.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/istream-raw-mbox.h Thu May 06 04:22:25 2004 +0300 @@ -10,10 +10,21 @@ 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);
--- a/src/lib-storage/index/mbox/mbox-expunge.c Tue May 04 21:13:10 2004 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/mbox/mbox-file.c Thu May 06 04:22:25 2004 +0300 @@ -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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/mbox/mbox-file.h Thu May 06 04:22:25 2004 +0300 @@ -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
--- a/src/lib-storage/index/mbox/mbox-from.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-from.c Thu May 06 04:22:25 2004 +0300 @@ -17,22 +17,28 @@ "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 @@ "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 @@ } 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 @@ /* 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 @@ /* 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 @@ 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)
--- a/src/lib-storage/index/mbox/mbox-from.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-from.h Thu May 06 04:22:25 2004 +0300 @@ -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
--- a/src/lib-storage/index/mbox/mbox-list.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-list.c Thu May 06 04:22:25 2004 +0300 @@ -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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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_none(struct mailbox_list_context *ctx __attr_unused__) +mbox_list_none(struct mbox_list_context *ctx __attr_unused__) { return NULL; } -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/mbox/mbox-lock.c Thu May 06 04:22:25 2004 +0300 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/mbox/mbox-lock.h Thu May 06 04:22:25 2004 +0300 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/mbox/mbox-mail.c Thu May 06 04:22:25 2004 +0300 @@ -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 +};
--- a/src/lib-storage/index/mbox/mbox-save.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-save.c Thu May 06 04:22:25 2004 +0300 @@ -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-storage.h" +#include "mbox-file.h" +#include "mbox-from.h" #include "mbox-lock.h" -#include "mbox-storage.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 @@ 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 @@ *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 @@ 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 @@ 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_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 @@ 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 @@ 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 @@ 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 @@ 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; + + ctx->flags = flags; + + if (ctx == NULL) { + ctx = t->save_ctx = i_new(struct mbox_save_context, 1); + ctx->ibox = ibox; + ctx->append_offset = (uoff_t)-1; + } - /* 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; + 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; + } + + 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) || - !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)) { + 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 { + ret = 0; + } + t_pop(); + return ret; +} + +static void mbox_save_deinit(struct mbox_save_context *ctx) +{ + if (ctx->output != NULL) + o_stream_unref(ctx->output); + i_free(ctx); +} + +int mbox_save_commit(struct mbox_save_context *ctx) +{ + int ret = 0; + + if (ctx->ibox->mbox_fd != -1) { + if (fdatasync(ctx->ibox->mbox_fd) < 0) { + mbox_set_syscall_error(ctx->ibox, "fsync()"); + ret = -1; + } + } + + mbox_save_deinit(ctx); + return ret; +} + +void mbox_save_rollback(struct mbox_save_context *ctx) +{ + struct index_mailbox *ibox = ctx->ibox; + + if (ctx->append_offset != (uoff_t)-1 && ibox->mbox_fd != -1) { + i_assert(ibox->mbox_lock_type == F_WRLCK); + /* 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; - } - failed = TRUE; - } else { - if (!ctx->transaction) - ctx->sync_offset = ctx->output->offset; - failed = FALSE; - } - t_pop(); - return !failed; -} - -struct mail_save_context * -mbox_storage_save_init(struct mailbox *box, int transaction) -{ - 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 (ftruncate(ibox->mbox_fd, (off_t)ctx->append_offset) < 0) + mbox_set_syscall_error(ibox, "ftruncate()"); } - if (!index_storage_sync_and_lock(ibox, FALSE, TRUE, - MAIL_LOCK_EXCLUSIVE)) - return NULL; - - ctx = i_new(struct mail_save_context, 1); - ctx->ibox = ibox; - ctx->transaction = transaction; - - if (!mbox_seek_to_end(ctx, &ctx->sync_offset)) { - i_free(ctx); - return NULL; - } - - 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); } - -int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback) -{ - int failed = FALSE; - - if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK)) - failed = TRUE; - - if (o_stream_flush(ctx->output) < 0) - failed = TRUE; - o_stream_unref(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; - } - } - - i_free(ctx); - return !failed; -} -#endif
--- a/src/lib-storage/index/mbox/mbox-storage.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-storage.c Thu May 06 04:22:25 2004 +0300 @@ -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-storage.h" #include "mbox-lock.h" -#include "mbox-storage.h" +#include "mail-save.h" #include <stdio.h> #include <stdlib.h> @@ -21,8 +21,19 @@ 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 @@ 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 @@ 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 @@ 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 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 @@ /* 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 @@ 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 = index_storage_mailbox_init(storage, &mbox_mailbox, index, - name, flags); - if (ibox != NULL) - ibox->mail_init = mbox_mail_init; - return (struct mailbox *) ibox; + ibox->path = i_strdup(path); + ibox->mbox_fd = -1; + + 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } - 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 @@ 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 @@ 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 @@ 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; + struct index_mailbox *ibox = (struct index_mailbox *)box; - /* 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); - - 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 @@ 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 @@ 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 @@ 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 };
--- a/src/lib-storage/index/mbox/mbox-storage.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-storage.h Thu May 06 04:22:25 2004 +0300 @@ -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 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); + struct mbox_save_context *save_ctx; + unsigned int mbox_lock_id; +}; + +extern struct mail mbox_mail; + +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); +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); -struct mail_expunge_context * -mbox_storage_expunge_init(struct mailbox *box, - enum mail_fetch_field wanted_fields, int expunge_all); -int mbox_storage_expunge_deinit(struct mail_expunge_context *ctx); -struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *ctx); -int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *ctx, - unsigned int *seq_r, int notify); +int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags); -const char *mbox_fix_mailbox_name(struct mail_storage *storage, +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);
--- a/src/lib-storage/index/mbox/mbox-sync-parse.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-parse.c Thu May 06 04:22:25 2004 +0300 @@ -85,27 +85,24 @@ return FALSE; } + /* <uid validity> <last uid> */ t_push(); - - /* <uid validity> <last uid> */ 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
--- a/src/lib-storage/index/mbox/mbox-sync-private.h Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-private.h Thu May 06 04:22:25 2004 +0300 @@ -25,7 +25,7 @@ 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_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_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 @@ 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,
--- a/src/lib-storage/index/mbox/mbox-sync-rewrite.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-rewrite.c Thu May 06 04:22:25 2004 +0300 @@ -19,7 +19,7 @@ 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_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;
--- a/src/lib-storage/index/mbox/mbox-sync.c Tue May 04 21:13:10 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync.c Thu May 06 04:22:25 2004 +0300 @@ -45,16 +45,21 @@ */ #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 @@ 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 @@ ret = -1; } - i_stream_unref(input); + if (fstat(ibox->mbox_fd, &st) < 0) { + mbox_set_syscall_error(ibox, "fstat()"); + ret = -1; + } + + if (ret < 0) { + st.st_mtime = 0; + st.st_size = 0; + } + + if (mail_index_sync_end(index_sync_ctx, st.st_mtime, st.st_size) < 0) + ret = -1; + + str_free(header); return ret < 0 ? -1 : 0; } -#if 0 -int mbox_sync(void) +int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags) { - 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; + struct index_mailbox *ibox = (struct index_mailbox *)box; - 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; + if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 || + ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) { + ibox->sync_last_check = ioloop_time; - 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 (mbox_sync(ibox, FALSE) < 0) + return -1; } - while (!ctx.input->eof) { - memset(&mail_ctx, 0, sizeof(mail_ctx)); - mail_ctx.parent = &ctx; - mail_ctx.header = header; - mail_ctx.seq = seq; - - 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); - - mbox_sync_mail_add_missing_headers(&mail_ctx); - - 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; - } - - if (ctx.first_spacy_msg_offset == 0) - ctx.first_spacy_msg_offset = mail_ctx.hdr_offset; - - ctx.prev_msg_uid = mail_ctx.uid; - istream_raw_mbox_next(ctx.input, mail_ctx.content_length); - } - str_free(header); - return 0; + return index_storage_sync(box, flags); } -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/mbox/mbox-transaction.c Thu May 06 04:22:25 2004 +0300 @@ -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); +}