[dovecot-cvs] dovecot/src/lib-storage/index/mbox mbox-file.c, NONE, 1.1 mbox-file.h, NONE, 1.1 mbox-lock.c, NONE, 1.1 mbox-lock.h, NONE, 1.1 mbox-mail.c, NONE, 1.1 mbox-transaction.c, NONE, 1.1 Makefile.am, 1.2, 1.3 istream-raw-mbox.c, 1.1, 1.2 istream-raw-mbox.h, 1.1, 1.2 mbox-from.c, 1.1, 1.2 mbox-from.h, 1.1, 1.2 mbox-list.c, 1.23, 1.24 mbox-save.c, 1.47, 1.48 mbox-storage.c, 1.73, 1.74 mbox-storage.h, 1.18, 1.19 mbox-sync-parse.c, 1.1, 1.2 mbox-sync-private.h, 1.2, 1.3 mbox-sync-rewrite.c, 1.1, 1.2 mbox-sync.c, 1.1, 1.2 mbox-expunge.c, 1.34, NONE

cras at procontrol.fi cras at procontrol.fi
Thu May 6 04:22:28 EEST 2004


Update of /home/cvs/dovecot/src/lib-storage/index/mbox
In directory talvi:/tmp/cvs-serv13512/src/lib-storage/index/mbox

Modified Files:
	Makefile.am istream-raw-mbox.c istream-raw-mbox.h mbox-from.c 
	mbox-from.h mbox-list.c mbox-save.c mbox-storage.c 
	mbox-storage.h mbox-sync-parse.c mbox-sync-private.h 
	mbox-sync-rewrite.c mbox-sync.c 
Added Files:
	mbox-file.c mbox-file.h mbox-lock.c mbox-lock.h mbox-mail.c 
	mbox-transaction.c 
Removed Files:
	mbox-expunge.c 
Log Message:
mbox code compiles again, but syncing is only partially implemented so
accessing mboxes fails..

Also some cleanups to index-storage and maildir code.



--- NEW FILE: mbox-file.c ---
/* 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;
	}
}

--- NEW FILE: mbox-file.h ---
#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

--- NEW FILE: mbox-lock.c ---
/* 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);
}

--- NEW FILE: mbox-lock.h ---
#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

--- NEW FILE: mbox-mail.c ---
/* 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
};

--- NEW FILE: mbox-transaction.c ---
/* 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);
}

Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/Makefile.am,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- Makefile.am	27 Apr 2004 20:25:54 -0000	1.2
+++ Makefile.am	6 May 2004 01:22:25 -0000	1.3
@@ -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

Index: istream-raw-mbox.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/istream-raw-mbox.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- istream-raw-mbox.c	27 Apr 2004 20:25:54 -0000	1.1
+++ istream-raw-mbox.c	6 May 2004 01:22:25 -0000	1.2
@@ -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 =

Index: istream-raw-mbox.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/istream-raw-mbox.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- istream-raw-mbox.h	27 Apr 2004 20:25:54 -0000	1.1
+++ istream-raw-mbox.h	6 May 2004 01:22:25 -0000	1.2
@@ -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);
 

Index: mbox-from.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-from.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- mbox-from.c	27 Apr 2004 20:25:54 -0000	1.1
+++ mbox-from.c	6 May 2004 01:22:25 -0000	1.2
@@ -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)

Index: mbox-from.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-from.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- mbox-from.h	27 Apr 2004 20:25:54 -0000	1.1
+++ mbox-from.h	6 May 2004 01:22:25 -0000	1.2
@@ -1,7 +1,8 @@
 #ifndef __MBOX_FROM_H
 #define __MBOX_FROM_H
 
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size);
+int mbox_from_parse(const unsigned char *msg, size_t size,
+		    time_t *time_r, char **sender_r);
 const char *mbox_from_create(const char *sender, time_t time);
 
 #endif

Index: mbox-list.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-list.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- mbox-list.c	27 Apr 2004 20:25:54 -0000	1.23
+++ mbox-list.c	6 May 2004 01:22:25 -0000	1.24
@@ -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

Index: mbox-save.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-save.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- mbox-save.c	2 May 2004 20:32:16 -0000	1.47
+++ mbox-save.c	6 May 2004 01:22:25 -0000	1.48
@@ -1,14 +1,14 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
-#if 0
 #include "lib.h"
 #include "hostpid.h"
 #include "ostream.h"
 #include "str.h"
 #include "write-full.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
 #include "mbox-storage.h"
+#include "mbox-file.h"
+#include "mbox-from.h"
+#include "mbox-lock.h"
 #include "mail-save.h"
 
 #include <stdlib.h>
@@ -17,9 +17,9 @@
 #include <sys/stat.h>
 #include <netdb.h>
 
-struct mail_save_context {
+struct mbox_save_context {
 	struct index_mailbox *ibox;
-	int transaction;
+	uoff_t append_offset;
 
 	struct ostream *output;
 	uoff_t sync_offset, content_length_offset, eoh_offset;
@@ -29,45 +29,37 @@
 
 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;
 
-	/* we don't need the real flag positions, easier to keep using our own.
-	   they need to be checked/added though. */
 	ctx->flags = flags;
-	real_flags = flags->flags;
-	if (!index_mailbox_fix_keywords(ctx->ibox, &real_flags,
-					flags->keywords,
-					flags->keywords_count))
-		return FALSE;
 
-	t_push();
-	if (!write_from_line(ctx, received_date) ||
-	    !mail_storage_save(ctx->ibox->box.storage,
-			       ctx->ibox->index->mailbox_path,
-			       data, ctx->output,
-			       getenv("MAIL_SAVE_CRLF") != NULL,
-			       save_header_callback, ctx) ||
-	    !mbox_fix_header(ctx) ||
-	    !mbox_append_lf(ctx)) {
-		/* failed, truncate file back to original size.
-		   output stream needs to be flushed before truncating
-		   so unref() won't write anything. */
-		o_stream_flush(ctx->output);
-		if (ctx->sync_offset != (uoff_t)-1) {
-			(void)ftruncate(ctx->ibox->index->mbox_fd,
-					ctx->sync_offset);
-			ctx->sync_offset = (uoff_t)-1;
+	if (ctx == NULL) {
+		ctx = t->save_ctx = i_new(struct mbox_save_context, 1);
+		ctx->ibox = ibox;
+		ctx->append_offset = (uoff_t)-1;
+	}
+
+	if (ctx->append_offset == (uoff_t)-1) {
+		if (ibox->mbox_lock_type != F_WRLCK) {
+			if (mbox_lock(ibox, F_WRLCK, &t->mbox_lock_id) <= 0)
+				return -1;
 		}
-		failed = TRUE;
+
+		if (ibox->mbox_fd == -1) {
+			if (mbox_file_open(ibox) < 0)
+				return -1;
+		}
+
+		if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0)
+			return -1;
+
+		ctx->output = o_stream_create_file(ibox->mbox_fd, default_pool,
+						   4096, FALSE);
+		o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
+	}
+
+	i_assert(ibox->mbox_lock_type == F_WRLCK);
+
+	t_push();
+	if (write_from_line(ctx, received_date, from_envelope) < 0 ||
+	    mail_storage_save(ibox->box.storage, ibox->path, data, ctx->output,
+			      getenv("MAIL_SAVE_CRLF") != NULL,
+			      save_header_callback, ctx) < 0 ||
+	    mbox_fix_header(ctx) < 0 ||
+	    mbox_append_lf(ctx) < 0) {
+		ret = -1;
 	} else {
-		if (!ctx->transaction)
-			ctx->sync_offset = ctx->output->offset;
-		failed = FALSE;
+		ret = 0;
 	}
 	t_pop();
-
-	return !failed;
+	return ret;
 }
 
-struct mail_save_context *
-mbox_storage_save_init(struct mailbox *box, int transaction)
+static void mbox_save_deinit(struct mbox_save_context *ctx)
 {
-	struct index_mailbox *ibox = (struct index_mailbox *) box;
-	struct mail_save_context *ctx;
-
-	if (box->is_readonly(box)) {
-		mail_storage_set_error(box->storage, "Mailbox is read-only");
-		return NULL;
-	}
-
-	if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
-					 MAIL_LOCK_EXCLUSIVE))
-		return NULL;
+	if (ctx->output != NULL)
+		o_stream_unref(ctx->output);
+	i_free(ctx);
+}
 
-	ctx = i_new(struct mail_save_context, 1);
-	ctx->ibox = ibox;
-	ctx->transaction = transaction;
+int mbox_save_commit(struct mbox_save_context *ctx)
+{
+	int ret = 0;
 
-	if (!mbox_seek_to_end(ctx, &ctx->sync_offset)) {
-		i_free(ctx);
-		return NULL;
+	if (ctx->ibox->mbox_fd != -1) {
+		if (fdatasync(ctx->ibox->mbox_fd) < 0) {
+			mbox_set_syscall_error(ctx->ibox, "fsync()");
+			ret = -1;
+		}
 	}
 
-	ctx->output = o_stream_create_file(ibox->index->mbox_fd,
-					   default_pool, 4096, FALSE);
-	o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
-	return ctx;
+	mbox_save_deinit(ctx);
+	return ret;
 }
 
-int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback)
+void mbox_save_rollback(struct mbox_save_context *ctx)
 {
-	int failed = FALSE;
+	struct index_mailbox *ibox = ctx->ibox;
 
-	if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK))
-		failed = TRUE;
+	if (ctx->append_offset != (uoff_t)-1 && ibox->mbox_fd != -1) {
+		i_assert(ibox->mbox_lock_type == F_WRLCK);
 
-	if (o_stream_flush(ctx->output) < 0)
-		failed = TRUE;
-	o_stream_unref(ctx->output);
+		/* failed, truncate file back to original size.
+		   output stream needs to be flushed before truncating
+		   so unref() won't write anything. */
+		o_stream_flush(ctx->output);
 
-	if (rollback && ctx->sync_offset != (uoff_t)-1) {
-		if (ftruncate(ctx->ibox->index->mbox_fd,
-			      ctx->sync_offset) < 0) {
-			syscall_error(ctx, "ftruncate()");
-			failed = TRUE;
-		}
-	} else {
-		if (fdatasync(ctx->ibox->index->mbox_fd) < 0) {
-			syscall_error(ctx, "fsync()");
-			failed = TRUE;
-		}
+		if (ftruncate(ibox->mbox_fd, (off_t)ctx->append_offset) < 0)
+			mbox_set_syscall_error(ibox, "ftruncate()");
 	}
 
-	i_free(ctx);
-	return !failed;
+	mbox_save_deinit(ctx);
 }
-#endif

Index: mbox-storage.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-storage.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- mbox-storage.c	2 May 2004 20:32:16 -0000	1.73
+++ mbox-storage.c	6 May 2004 01:22:25 -0000	1.74
@@ -1,14 +1,14 @@
 /* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
+#include "buffer.h"
 #include "home-expand.h"
 #include "mkdir-parents.h"
 #include "unlink-directory.h"
 #include "subscription-file/subscription-file.h"
-#include "mail-keywords.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
 #include "mbox-storage.h"
+#include "mbox-lock.h"
+#include "mail-save.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -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;
-
-	/* update flags by rewrite mbox file */
-        index_storage_init_lock_notify(ibox);
-	if (!ibox->index->mailbox_readonly) {
-		if (!mbox_index_rewrite(ibox->index)) {
-			mail_storage_set_index_error(ibox);
-			failed = TRUE;
-		}
-	}
-	ibox->index->set_lock_notify_callback(ibox->index, NULL, NULL);
+	struct index_mailbox *ibox = (struct index_mailbox *)box;
 
-	return index_storage_mailbox_free(box) && !failed;
+	if (ibox->mbox_data_buf != NULL)
+		buffer_free(ibox->mbox_data_buf);
+        index_storage_mailbox_free(box);
+	return 0;
 }
 
 static void mbox_storage_auto_sync(struct mailbox *box,
 				   enum mailbox_sync_flags flags,
 				   unsigned int min_newmail_notify_interval)
 {
-	struct index_mailbox *ibox = (struct index_mailbox *) box;
+	struct index_mailbox *ibox = (struct index_mailbox *)box;
 
 	ibox->min_newmail_notify_interval = min_newmail_notify_interval;
 
@@ -780,40 +799,7 @@
 	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
 };

Index: mbox-storage.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-storage.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- mbox-storage.h	27 Jul 2003 03:12:13 -0000	1.18
+++ mbox-storage.h	6 May 2004 01:22:25 -0000	1.19
@@ -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 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);
+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);
 
-const char *mbox_fix_mailbox_name(struct mail_storage *storage,
+int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+
+int mbox_save(struct mailbox_transaction_context *t,
+	      const struct mail_full_flags *flags,
+	      time_t received_date, int timezone_offset,
+	      const char *from_envelope, struct istream *data);
+int mbox_save_commit(struct mbox_save_context *ctx);
+void mbox_save_rollback(struct mbox_save_context *ctx);
+
+const char *mbox_fix_mailbox_name(struct index_storage *istorage,
 				  const char *name, int remove_namespace);
 int mbox_is_valid_mask(const char *mask);
 

Index: mbox-sync-parse.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-parse.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- mbox-sync-parse.c	27 Apr 2004 20:25:54 -0000	1.1
+++ mbox-sync-parse.c	6 May 2004 01:22:25 -0000	1.2
@@ -85,27 +85,24 @@
 		return FALSE;
 	}
 
-	t_push();
-
 	/* <uid validity> <last uid> */
+	t_push();
 	str = t_strndup(hdr->full_value, hdr->full_value_len);
 	ctx->base_uid_validity = strtoul(str, &end, 10);
 	ctx->base_uid_last = strtoul(end, &end, 10);
 	pos = end - str;
+	t_pop();
 
 	while (pos < hdr->full_value_len && IS_LWSP_LF(hdr->full_value[pos]))
 		pos++;
 
 	if (ctx->base_uid_validity == 0) {
 		/* broken */
-		t_pop();
 		return FALSE;
 	}
 
-	if (pos == hdr->full_value_len) {
-		t_pop();
+	if (pos == hdr->full_value_len)
 		return TRUE;
-	}
 
 	// FIXME: save keywords
 

Index: mbox-sync-private.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-private.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- mbox-sync-private.h	2 May 2004 20:32:16 -0000	1.2
+++ mbox-sync-private.h	6 May 2004 01:22:25 -0000	1.3
@@ -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,

Index: mbox-sync-rewrite.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-rewrite.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- mbox-sync-rewrite.c	27 Apr 2004 20:25:54 -0000	1.1
+++ mbox-sync-rewrite.c	6 May 2004 01:22:25 -0000	1.2
@@ -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;
 

Index: mbox-sync.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- mbox-sync.c	27 Apr 2004 20:25:54 -0000	1.1
+++ mbox-sync.c	6 May 2004 01:22:25 -0000	1.2
@@ -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);
-	return ret < 0 ? -1 : 0;
-}
-
-#if 0
-int mbox_sync(void)
-{
-	struct mail_index_view *sync_view;
-	struct mail_index_sync_ctx *sync_ctx;
-	struct mail_index_sync_rec sync_rec;
-	struct mbox_sync_context ctx;
-	struct mbox_sync_mail_context mail_ctx;
-	struct mbox_mail mail;
-	string_t *header;
-	uint32_t seq;
-	unsigned int need_space_seq;
-	uoff_t missing_space;
-	buffer_t *mails;
-	int ret;
-
-	memset(&ctx, 0, sizeof(ctx));
-	/*ctx.index = storage->index;
-	ctx.input = storage->input;*/
-	ctx.fd = i_stream_get_fd(ctx.input);
-
-	header = str_new(default_pool, 4096);
-
-	if (mail_index_sync_begin(ctx.index, &sync_ctx, &sync_view, 0, 0) < 0)
-		return -1;
-
-	ctx.hdr = mail_index_get_header(sync_view);
-	ctx.next_uid = ctx.hdr->next_uid;
-
-	seq = 1;
-	while ((ret = mail_index_sync_next(sync_ctx, &sync_rec)) > 0) {
-		while (seq < sync_rec.seq1) {
-			seq++;
-		}
-		switch (sync_rec.type) {
-		case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
-			break;
-		case MAIL_INDEX_SYNC_TYPE_FLAGS:
-			break;
-		}
+	if (fstat(ibox->mbox_fd, &st) < 0) {
+		mbox_set_syscall_error(ibox, "fstat()");
+		ret = -1;
 	}
 
-	while (!ctx.input->eof) {
-		memset(&mail_ctx, 0, sizeof(mail_ctx));
-		mail_ctx.parent = &ctx;
-		mail_ctx.header = header;
-		mail_ctx.seq = seq;
+	if (ret < 0) {
+		st.st_mtime = 0;
+		st.st_size = 0;
+	}
 
-		mail_ctx.hdr_offset = ctx.input->v_offset;
-		mbox_sync_mail_parse_headers(&mail_ctx);
-		mail_ctx.body_offset = ctx.input->v_offset;
-		mail_ctx.body_size =
-			istream_raw_mbox_get_size(ctx.input,
-						  mail_ctx.content_length);
+	if (mail_index_sync_end(index_sync_ctx, st.st_mtime, st.st_size) < 0)
+		ret = -1;
 
-                mbox_sync_mail_add_missing_headers(&mail_ctx);
+	str_free(header);
+	return ret < 0 ? -1 : 0;
+}
 
-		ret = mbox_sync_try_rewrite_headers(&mail_ctx, &missing_space);
-		if (ret < 0)
-			break;
-		if (missing_space != 0) {
-			ctx.space_diff -= missing_space;
-		} else {
-			ctx.space_diff += mail_ctx.extra_space;
-		}
+int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+{
+	struct index_mailbox *ibox = (struct index_mailbox *)box;
 
-		if (ctx.first_spacy_msg_offset == 0)
-                        ctx.first_spacy_msg_offset = mail_ctx.hdr_offset;
+	if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
+	    ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
+		ibox->sync_last_check = ioloop_time;
 
-		ctx.prev_msg_uid = mail_ctx.uid;
-		istream_raw_mbox_next(ctx.input, mail_ctx.content_length);
+		if (mbox_sync(ibox, FALSE) < 0)
+			return -1;
 	}
-	str_free(header);
-	return 0;
+
+	return index_storage_sync(box, flags);
 }
-#endif

--- mbox-expunge.c DELETED ---



More information about the dovecot-cvs mailing list