changeset 22:a946ce1f09b7 HEAD

mbox fixes, not fully working yet but almost :)
author Timo Sirainen <tss@iki.fi>
date Sat, 24 Aug 2002 05:04:45 +0300
parents 163675942b83
children 6cefb1763f3e
files src/imap/main.c src/lib-imap/imap-message-cache.c src/lib-imap/imap-message-cache.h src/lib-imap/imap-parser.c src/lib-index/Makefile.am src/lib-index/mail-index-update.c src/lib-index/mail-index.h src/lib-index/mbox/Makefile.am src/lib-index/mbox/mbox-append.c src/lib-index/mbox/mbox-fsck.c src/lib-index/mbox/mbox-index.c src/lib-index/mbox/mbox-index.h src/lib-index/mbox/mbox-open.c src/lib-index/mbox/mbox-rebuild.c src/lib-index/mbox/mbox-sync.c src/lib-storage/index/index-copy.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib/iobuffer.c src/lib/iobuffer.h
diffstat 23 files changed, 564 insertions(+), 430 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/main.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/imap/main.c	Sat Aug 24 05:04:45 2002 +0300
@@ -55,7 +55,7 @@
 			mail = t_strconcat("maildir:", mail, NULL);
 	}
 
-	storage = mail_storage_create_with_data(mail);
+	storage = mail_storage_create_with_data(mail, getenv("USER"));
 	if (storage == NULL) {
 		/* failed */
 		if (mail != NULL && *mail != '\0')
--- a/src/lib-imap/imap-message-cache.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-imap/imap-message-cache.c	Sat Aug 24 05:04:45 2002 +0300
@@ -45,7 +45,7 @@
 
 	CachedMessage *open_msg;
 	IOBuffer *open_inbuf;
-	size_t open_size, open_virtual_size;
+	off_t open_virtual_size;
 
 	IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf, void *context);
 	void *context;
@@ -292,8 +292,14 @@
 			message_get_header_size(cache->open_inbuf,
 						msg->hdr_size);
 
+			i_assert((off_t)msg->hdr_size->physical_size <
+				 cache->open_inbuf->size);
+			i_assert((off_t)msg->hdr_size->virtual_size <
+				 cache->open_virtual_size);
+
 			msg->body_size->lines = 0;
-			msg->body_size->physical_size = cache->open_size -
+			msg->body_size->physical_size =
+				cache->open_inbuf->size -
 				msg->hdr_size->physical_size;
 			msg->body_size->virtual_size =
 				cache->open_virtual_size -
@@ -320,8 +326,8 @@
 }
 
 void imap_msgcache_message(ImapMessageCache *cache, unsigned int uid,
-			   ImapCacheField fields, size_t virtual_size,
-			   size_t pv_headers_size, size_t pv_body_size,
+			   ImapCacheField fields, off_t virtual_size,
+			   off_t pv_headers_size, off_t pv_body_size,
 			   IOBuffer *inbuf,
 			   IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf,
 						     void *context),
@@ -335,8 +341,6 @@
 
 		cache->open_msg = msg;
 		cache->open_inbuf = inbuf;
-		cache->open_size = cache->open_inbuf->stop_offset -
-			cache->open_inbuf->offset;
 		cache->open_virtual_size = virtual_size;
 
 		cache->inbuf_rewind = inbuf_rewind;
@@ -369,7 +373,7 @@
 	}
 
 	cache->open_msg = NULL;
-	cache->open_size = cache->open_virtual_size = 0;
+	cache->open_virtual_size = 0;
 }
 
 void imap_msgcache_set(ImapMessageCache *cache, unsigned int uid,
@@ -538,7 +542,8 @@
 	if (virtual_skip == 0) {
 		if (max_virtual_size < 0 && msg->body_size == NULL) {
 			msg->body_size = p_new(msg->pool, MessageSize, 1);
-			msg->body_size->physical_size = cache->open_size -
+			msg->body_size->physical_size =
+				cache->open_inbuf->size -
 				msg->hdr_size->physical_size;
 			msg->body_size->virtual_size =
 				cache->open_virtual_size -
--- a/src/lib-imap/imap-message-cache.h	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-imap/imap-message-cache.h	Sat Aug 24 05:04:45 2002 +0300
@@ -37,8 +37,8 @@
    non-zero, they're set to saved to message's both physical and virtual
    sizes (ie. doesn't need to be calculated). */
 void imap_msgcache_message(ImapMessageCache *cache, unsigned int uid,
-			   ImapCacheField fields, size_t virtual_size,
-			   size_t pv_headers_size, size_t pv_body_size,
+			   ImapCacheField fields, off_t virtual_size,
+			   off_t pv_headers_size, off_t pv_body_size,
 			   IOBuffer *inbuf,
 			   IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf,
 						     void *context),
--- a/src/lib-imap/imap-parser.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-imap/imap-parser.c	Sat Aug 24 05:04:45 2002 +0300
@@ -284,7 +284,8 @@
 	/* expecting digits + "}" */
 	for (i = parser->cur_pos; i < data_size; i++) {
 		if (data[i] == '}') {
-			if (parser->literal_size > parser->inbuf->max_size) {
+			if (parser->literal_size >
+			    parser->inbuf->max_buffer_size) {
 				/* too long string, abort. */
 				parser->error = TRUE;
 				return FALSE;
--- a/src/lib-index/Makefile.am	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/Makefile.am	Sat Aug 24 05:04:45 2002 +0300
@@ -1,4 +1,4 @@
-SUBDIRS = maildir
+SUBDIRS = maildir mbox
 
 noinst_LIBRARIES = libstorage_index.a
 
--- a/src/lib-index/mail-index-update.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mail-index-update.c	Sat Aug 24 05:04:45 2002 +0300
@@ -383,8 +383,7 @@
 				     update_header_func, &ctx);
 
 		update->rec->header_size = hdr_size.physical_size;
-		update->rec->body_size = (inbuf->stop_offset - inbuf->offset) -
-			hdr_size.physical_size;
+		update->rec->body_size = inbuf->size - inbuf->offset;
 
 		if (update->rec->full_virtual_size == 0) {
 			/* we need to calculate virtual size of the
--- a/src/lib-index/mail-index.h	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mail-index.h	Sat Aug 24 05:04:45 2002 +0300
@@ -43,9 +43,10 @@
 	FIELD_TYPE_CC			= 0x0080,
 	FIELD_TYPE_BCC			= 0x0100,
 	FIELD_TYPE_SUBJECT		= 0x0200,
+	FIELD_TYPE_MD5			= 0x0400,
 
-	FIELD_TYPE_LAST			= 0x0400,
-	FIELD_TYPE_MAX_BITS		= 10
+	FIELD_TYPE_LAST			= 0x0800,
+	FIELD_TYPE_MAX_BITS		= 11
 } MailField;
 
 #define IS_HEADER_FIELD(field) \
--- a/src/lib-index/mbox/Makefile.am	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/Makefile.am	Sat Aug 24 05:04:45 2002 +0300
@@ -8,6 +8,7 @@
 
 libstorage_index_mbox_a_SOURCES = \
 	mbox-append.c \
+	mbox-from.c \
 	mbox-fsck.c \
 	mbox-index.c \
 	mbox-lock.c \
--- a/src/lib-index/mbox/mbox-append.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-append.c	Sat Aug 24 05:04:45 2002 +0300
@@ -1,21 +1,13 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
-#include "mmap-util.h"
 #include "ioloop.h"
+#include "iobuffer.h"
+#include "hex-binary.h"
+#include "md5.h"
 #include "mbox-index.h"
 #include "mail-index-util.h"
 
-#include <time.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-static const char *months[] = {
-	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
 static MailIndexRecord *
 mail_index_record_append(MailIndex *index, time_t internal_date,
 			 size_t full_virtual_size)
@@ -33,123 +25,102 @@
 	return rec;
 }
 
-static time_t from_line_parse_date(const char *msg, size_t size)
+static void mbox_read_message(IOBuffer *inbuf, unsigned int *virtual_size)
 {
-	const char *msg_end;
-	struct tm tm;
-	int i;
-
-	/* From <sender> <date> <moreinfo> */
-	if (strncmp(msg, "From ", 5) != 0)
-		return 0;
-
-	msg_end = msg + size;
+	unsigned char *msg;
+	unsigned int i, size, startpos, vsize;
 
-	/* skip sender */
-	msg += 5;
-	while (*msg != ' ' && msg < msg_end) msg++;
-	while (*msg == ' ' && msg < msg_end) msg++;
-
-	/* next 24 chars are the date in asctime() format,
-	   eg. "Thu Nov 29 22:33:52 2001" */
-	if (msg+24 > msg_end)
-		return 0;
+	/* read until "[\r]\nFrom " is found */
+	startpos = 0; vsize = 0;
+	while (io_buffer_read_data(inbuf, &msg, &size, startpos) >= 0) {
+		for (i = startpos; i < size; i++) {
+			if (msg[i] == '\n') {
+				if (i == 0 || msg[i-1] != '\r') {
+					/* missing CR */
+					vsize++;
+				}
+			} else if (msg[i] == ' ' && i >= 5) {
+				/* See if it's space after "From" */
+				if (msg[i-5] == '\n' && msg[i-4] == 'F' &&
+				    msg[i-3] == 'r' && msg[i-2] == 'o' &&
+				    msg[i-1] == 'm') {
+					/* yes, see if we had \r too */
+					i -= 5;
+					if (i > 0 && msg[i-1] == '\r')
+						i--;
+					else
+						vsize--;
+					break;
+				}
+			}
+		}
 
-	memset(&tm, 0, sizeof(tm));
-
-	/* skip weekday */
-	msg += 4;
+		if (i < size) {
+			startpos = i;
+			break;
+		}
 
-	/* month */
-	for (i = 0; i < 12; i++) {
-		if (strncasecmp(months[i], msg, 3) == 0) {
-			tm.tm_mon = i;
-			break;
+		if (i > 0) {
+			startpos = i < 7 ? i : 7;
+			i -= startpos;
+
+			io_buffer_skip(inbuf, i);
+			vsize += i;
 		}
 	}
 
-	if (i == 12 || msg[3] != ' ')
-		return 0;
-	msg += 4;
-
-	/* day */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
-		return 0;
-	tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0');
-	msg += 3;
-
-	/* hour */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
-		return 0;
-	tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0');
-	msg += 3;
+	io_buffer_skip(inbuf, startpos);
+	vsize += startpos;
 
-	/* minute */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
-		return 0;
-	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 0;
-	tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0');
-	msg += 3;
-
-	/* year */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
-	    !i_isdigit(msg[2]) || !i_isdigit(msg[3]))
-		return 0;
-	tm.tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 +
-		(msg[2]-'0') * 10 + (msg[3]-'0') - 1900;
-
-	tm.tm_isdst = -1;
-	return mktime(&tm);
+	*virtual_size = vsize;
 }
 
-static void header_func(MessagePart *part __attr_unused__,
-			const char *name, unsigned int name_len,
-			const char *value, unsigned int value_len,
-			void *context)
-{
-	MailIndexRecord *rec = context;
-
-	rec->msg_flags |= mbox_header_get_flags(name, name_len,
-						value, value_len);
-}
-
-static int mbox_index_append_data(MailIndex *index, const char *msg,
-				  off_t offset, size_t physical_size,
-				  size_t virtual_size)
+static int mbox_index_append_next(MailIndex *index, IOBuffer *inbuf)
 {
 	MailIndexRecord *rec;
 	MailIndexUpdate *update;
+        MboxHeaderContext ctx;
 	time_t internal_date;
-	char location[MAX_INT_STRLEN];
-	unsigned int i;
+	off_t start_offset, stop_offset, old_size;
+	unsigned char *data, md5_digest[16];
+	unsigned int size, pos, virtual_size;
+	const char *location;
+
+	/* get the From-line */
+	pos = 0;
+	while (io_buffer_read_data(inbuf, &data, &size, pos) >= 0) {
+		for (; pos < size; pos++) {
+			if (data[pos] == '\n')
+				break;
+		}
 
-	internal_date = from_line_parse_date(msg, physical_size);
+		if (pos < size)
+			break;
+	}
+
+	if (pos == size || size <= 5 || strncmp(data, "From ", 5) != 0) {
+		/* a) no \n found, or line too long
+		   b) not a From-line */
+		index_set_error(index, "Error indexing mbox file %s: "
+				"From-line not found where expected",
+				index->mbox_path);
+		index->set_flags |= MAIL_INDEX_FLAG_FSCK;
+		return FALSE;
+	}
+
+	/* parse the From-line */
+	internal_date = mbox_from_parse_date(data, size);
 	if (internal_date <= 0)
 		internal_date = ioloop_time;
 
-	/* skip the From-line */
-	for (i = 0; i < physical_size; i++) {
-		if (msg[i] == '\n') {
-			i++;
-			break;
-		}
-	}
+	io_buffer_skip(inbuf, pos+1);
+	start_offset = inbuf->offset;
 
-	if (i == physical_size)
-		return FALSE;
+	/* now, find the ending "[\r]\nFrom " */
+	mbox_read_message(inbuf, &virtual_size);
+	stop_offset = inbuf->offset;
 
-	msg += i;
-	offset += i;
-	physical_size -= i;
-	virtual_size -= i;
-	if (i > 0 && msg[i-1] != '\r')
-		virtual_size--;
-
+	/* add message to index */
 	rec = mail_index_record_append(index, internal_date, virtual_size);
 	if (rec == NULL)
 		return FALSE;
@@ -157,11 +128,32 @@
 	update = index->update_begin(index, rec);
 
 	/* location = offset to beginning of message */
-	i_snprintf(location, sizeof(location), "%lu", (unsigned long) offset);
+	location = binary_to_hex((unsigned char *) &start_offset,
+				 sizeof(start_offset));
 	index->update_field(update, FIELD_TYPE_LOCATION, location, 0);
 
-	/* parse the header and cache wanted fields */
-	mail_index_update_headers(update, msg, physical_size, header_func, rec);
+	/* parse the header and cache wanted fields. get the message flags
+	   from Status and X-Status fields. temporarily limit the buffer size
+	   so the message body is parsed properly (FIXME: does this have
+	   side effects?) */
+	mbox_header_init_context(&ctx);
+
+        old_size = inbuf->size;
+	inbuf->size = stop_offset;
+	io_buffer_seek(inbuf, start_offset);
+
+	mail_index_update_headers(update, inbuf, mbox_header_func, &ctx);
+
+	inbuf->size = old_size;
+	io_buffer_seek(inbuf, stop_offset);
+
+	/* save message flags */
+	rec->msg_flags |= ctx.flags;
+
+	/* save MD5 */
+	md5_final(&ctx.md5, md5_digest);
+	index->update_field(update, FIELD_TYPE_MD5,
+                            binary_to_hex(md5_digest, sizeof(md5_digest)), 0);
 
 	if (!index->update_end(update)) {
 		/* failed - delete the record */
@@ -172,79 +164,9 @@
 	return TRUE;
 }
 
-int mbox_index_append_mmaped(MailIndex *index, const char *data,
-			     size_t data_size, off_t start_offset)
+int mbox_index_append(MailIndex *index, IOBuffer *inbuf)
 {
-	const char *data_start, *data_end, *start, *cr;
-	size_t size, vsize;
-	off_t pos;
-	int missing_cr_count;
-
-	/* we should start with "From ". if we don't, something's messed up
-	   and we should check the whole file instead. */
-	if (strncmp(data, "From ", 5) != 0) {
-		index->set_flags |= MAIL_INDEX_FLAG_FSCK;
-		return FALSE;
-	}
-
-	/* each message ends at "\nFrom ". first get the size of the message,
-	   then parse it. calculate the missing CR count as well. */
-	start = data; cr = NULL; missing_cr_count = 0;
-
-	data_start = data;
-	data_end = data + data_size;
-	for (; data != data_end; data++) {
-		if (*data == '\r')
-			cr = data;
-		else if (*data == '\n') {
-			if (cr != data-1)
-				missing_cr_count++;
-
-			if (data+6 < data_end && data[1] == 'F' &&
-			    data[2] == 'r' && data[3] == 'o' &&
-			    data[4] == 'm' && data[5] == ' ') {
-				/* end of message */
-				pos = (off_t) (start - data_start) +
-					start_offset;
-				size = (size_t) (data - start) + 1;
-				vsize = size + missing_cr_count;
-				if (!mbox_index_append_data(index, start, pos,
-							    size, vsize))
-					return FALSE;
-
-				missing_cr_count = 0;
-				start = data+1;
-			}
-		}
-	}
-
-	/* last message */
-	pos = (off_t) (start - data_start);
-	size = (size_t) (data - start);
-	vsize = size + missing_cr_count;
-	return mbox_index_append_data(index, start, pos, size, vsize);
-}
-
-int mbox_index_append(MailIndex *index, int fd, const char *path)
-{
-	void *mmap_base;
-	size_t mmap_length;
-	off_t pos, end_pos;
-	int ret;
-
-	/* get our current position */
-	pos = lseek(fd, 0, SEEK_CUR);
-
-	/* get the size of the file */
-	end_pos = lseek(fd, 0, SEEK_END);
-
-	if (pos == -1 || end_pos == -1) {
-		index_set_error(index, "lseek() failed with mbox file %s: %m",
-				path);
-		return FALSE;
-	}
-
-	if (pos == end_pos) {
+	if (inbuf->offset == inbuf->size) {
 		/* no new data */
 		return TRUE;
 	}
@@ -252,18 +174,27 @@
 	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
 		return FALSE;
 
-	/* mmap() the file */
-	mmap_length = end_pos-pos;
-	mmap_base = mmap(NULL, mmap_length, PROT_READ, MAP_SHARED, fd, pos);
-	if (mmap_base == MAP_FAILED) {
-		index_set_error(index, "mmap() failed with mbox file %s: %m",
-				path);
-		return FALSE;
+	for (;;) {
+		if (inbuf->offset != 0) {
+			/* we're at the [\r]\n before the From-line,
+			   skip it */
+			if (!mbox_skip_crlf(inbuf)) {
+				index_set_error(index,
+						"Error indexing mbox file %s: "
+						"LF not found where expected",
+						index->mbox_path);
+
+				index->set_flags |= MAIL_INDEX_FLAG_FSCK;
+				return FALSE;
+			}
+		}
+
+		if (inbuf->offset == inbuf->size)
+			break;
+
+		if (!mbox_index_append_next(index, inbuf))
+			return FALSE;
 	}
 
-	(void)madvise(mmap_base, mmap_length, MADV_SEQUENTIAL);
-
-	ret = mbox_index_append_mmaped(index, mmap_base, mmap_length, pos);
-	(void)munmap(mmap_base, mmap_length);
-	return ret;
+	return TRUE;
 }
--- a/src/lib-index/mbox/mbox-fsck.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-fsck.c	Sat Aug 24 05:04:45 2002 +0300
@@ -1,106 +1,122 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
-#include "mmap-util.h"
+#include "iobuffer.h"
+#include "hex-binary.h"
 #include "message-parser.h"
 #include "mbox-index.h"
 #include "mbox-lock.h"
 #include "mail-index-util.h"
 
+#include <unistd.h>
 #include <fcntl.h>
 
-typedef struct {
-	const char *msgid;
-	MailFlags flags;
-} HeaderContext;
+static void skip_line(IOBuffer *inbuf)
+{
+	unsigned char *msg;
+	unsigned int i, size;
 
-static void header_func(MessagePart *part __attr_unused__,
-			const char *name, unsigned int name_len,
-			const char *value, unsigned int value_len,
-			void *context)
-{
-	HeaderContext *ctx = context;
+	while (io_buffer_read_data(inbuf, &msg, &size, 0) >= 0) {
+		for (i = 0; i < size; i++) {
+			if (msg[i] == '\n')
+				break;
+		}
 
-	if (name_len != 10 || strncasecmp(name, "Message-ID", 10) != 0)
-		return;
+		if (i < size) {
+			io_buffer_skip(inbuf, i+1);
+			break;
+		}
 
-	ctx->msgid = t_strndup(value, value_len);
-	ctx->flags |= mbox_header_get_flags(name, name_len, value, value_len);
+		io_buffer_skip(inbuf, i);
+	}
 }
 
 static MailIndexRecord *
 match_next_record(MailIndex *index, MailIndexRecord *rec, unsigned int *seq,
-		  const char **data, const char *data_end)
+		  IOBuffer *inbuf)
 {
-#if 0 // FIXME
 	MessageSize hdr_size;
-        HeaderData hdr_data;
-	const char *rec_msgid, *data_next;
+	MboxHeaderContext ctx;
+	off_t old_offset;
+	unsigned char *data, current_digest[16], old_digest[16];
+	unsigned int size;
+	const char *md5sum;
 
 	/* skip the From-line */
-	while (*data != data_end && **data != '\n')
-		(*data)++;
-	(*data)++;
+	skip_line(inbuf);
 
-	if (*data >= data_end) {
-		/* end of data */
-		(void)index->expunge(index, rec, *seq, TRUE);
-		return rec;
-	}
-
-	/* find the Message-ID from the header */
-	memset(&hdr_data, 0, sizeof(hdr_data));
-	message_parse_header(NULL, *data, (size_t) (data_end-*data), &hdr_size,
-			     header_func, &hdr_data);
+	/* get the MD5 sum of fixed headers and the current message flags
+	   in Status and X-Status fields */
+        mbox_header_init_context(&ctx);
+	message_parse_header(NULL, inbuf, &hdr_size, mbox_header_func, &ctx);
+	md5_final(&ctx.md5, current_digest);
 
 	do {
+		old_offset = inbuf->offset;
 		do {
-			/* message-id must match (or be non-existant) */
-			rec_msgid = index->lookup_field(index, rec,
-							FIELD_TYPE_MESSAGEID);
-			if (hdr_data.msgid == NULL && rec_msgid != NULL)
+			/* MD5 sums must match */
+			md5sum = index->lookup_field(index, rec,
+						     FIELD_TYPE_MD5);
+			if (md5sum == NULL || strlen(md5sum) != 32 ||
+			    hex_to_binary(md5sum, old_digest) <= 0)
 				break;
-			if (hdr_data.msgid != NULL &&
-			    (rec_msgid == NULL ||
-			     strcmp(hdr_data.msgid, rec_msgid) != 0))
+
+			if (memcmp(old_digest, current_digest, 16) != 0)
 				break;
 
 			/* don't bother parsing the whole body, just make
 			   sure it ends properly */
-			data_next = *data + rec->header_size + rec->body_size;
-			if (data_next == data_end) {
+			io_buffer_skip(inbuf, rec->body_size);
+
+			if (inbuf->offset == inbuf->size) {
 				/* last message */
-			} else if (data_next+5 >= data_end ||
-				   strncmp(data_next-1, "\nFrom ", 6) != 0)
-				break;
+			} else {
+				/* read forward a bit */
+				if (io_buffer_read_data(inbuf, &data,
+							&size, 6) <= 0 ||
+				    size < 7)
+					break;
+
+				if (data[0] == '\r')
+					data++;
+				if (strncmp(data, "\nFrom ", 6) != 0)
+					break;
+			}
 
 			/* valid message, update flags */
-			if ((rec->msg_flags & hdr_data.flags) != hdr_data.flags)
-				rec->msg_flags |= hdr_data.flags;
-
-			*data = data_next;
+			if ((rec->msg_flags & ctx.flags) != ctx.flags)
+				rec->msg_flags |= ctx.flags;
 			return rec;
 		} while (0);
 
+		/* get back to beginning of message body */
+		if (inbuf->offset != old_offset)
+			io_buffer_seek(inbuf, old_offset);
+
 		/* try next message */
 		(*seq)++;
 		(void)index->expunge(index, rec, *seq, TRUE);
 		rec = index->next(index, rec);
 	} while (rec != NULL);
-#endif
+
 	return NULL;
 }
 
-static int mbox_index_fsck_mmap(MailIndex *index, const char *data, size_t size)
+static int mbox_index_fsck_buf(MailIndex *index, IOBuffer *inbuf)
 {
 	MailIndexRecord *rec;
-	const char *data_end;
-	unsigned int seq;
+	unsigned char *data;
+	unsigned int seq, size;
 
 	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
 		return FALSE;
 
 	/* first make sure we start with a "From " line. */
+	while (io_buffer_read_data(inbuf, &data, &size, 5) >= 0) {
+		if (size > 5)
+			break;
+	}
+
 	if (size <= 5 || strncmp(data, "From ", 5) != 0) {
 		index_set_error(index, "File isn't in mbox format: %s",
 				index->mbox_path);
@@ -118,9 +134,21 @@
 	seq = 1;
 	rec = index->lookup(index, 1);
 
-	data_end = data + size;
 	while (rec != NULL) {
-		rec = match_next_record(index, rec, &seq, &data, data_end);
+		if (inbuf->offset != 0) {
+			/* we're at the [\r]\n before the From-line,
+			   skip it */
+			if (!mbox_skip_crlf(inbuf)) {
+				/* they just went and broke it, even while
+				   we had it locked. */
+				return FALSE;
+			}
+		}
+
+		if (inbuf->offset == inbuf->size)
+			break;
+
+		rec = match_next_record(index, rec, &seq, inbuf);
 		if (rec == NULL)
 			break;
 
@@ -128,18 +156,15 @@
 		rec = index->next(index, rec);
 	}
 
-	if (data == data_end)
+	if (inbuf->offset == inbuf->size)
 		return TRUE;
-	else {
-		return mbox_index_append_mmaped(index, data,
-						(size_t) (data_end-data), 0);
-	}
+	else
+		return mbox_index_append(index, inbuf);
 }
 
 int mbox_index_fsck(MailIndex *index)
 {
-	void *mmap_base;
-	size_t mmap_length;
+	IOBuffer *inbuf;
 	int fd, failed;
 
 	/* open the mbox file. we don't really need to open it read-write,
@@ -151,31 +176,20 @@
 		return FALSE;
 	}
 
-	mmap_base = mmap_ro_file(fd, &mmap_length);
-	if (mmap_base == MAP_FAILED) {
-		index_set_error(index, "mmap() failed with mbox file %s: %m",
-				index->mbox_path);
-		return FALSE;
-	}
-	(void)madvise(mmap_base, mmap_length, MADV_SEQUENTIAL);
-
-	if (mmap_base == NULL) {
-		/* file is empty */
-		(void)close(fd);
-		return TRUE;
-	}
+	inbuf = io_buffer_create_mmap(fd, default_pool,
+				      MAIL_MMAP_BLOCK_SIZE, -1);
 
 	/* lock the mailbox so we can be sure no-one interrupts us.
 	   we are trying to repair our index after all. */
 	if (!mbox_lock(index, index->mbox_path, fd))
 		failed = TRUE;
 	else {
-		failed = !mbox_index_fsck_mmap(index, mmap_base, mmap_length);
+		failed = !mbox_index_fsck_buf(index, inbuf);
 		(void)mbox_unlock(index, index->mbox_path, fd);
 	}
 
-	(void)munmap(mmap_base, mmap_length);
 	(void)close(fd);
+	io_buffer_destroy(inbuf);
 
 	if (failed)
 		return FALSE;
--- a/src/lib-index/mbox/mbox-index.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-index.c	Sat Aug 24 05:04:45 2002 +0300
@@ -1,41 +1,140 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "iobuffer.h"
 #include "mbox-index.h"
 #include "mail-index-util.h"
 
 static MailIndex mbox_index;
 
-MailFlags mbox_header_get_flags(const char *name, unsigned int name_len,
-				const char *value, unsigned int value_len)
+void mbox_header_init_context(MboxHeaderContext *ctx)
+{
+	memset(ctx, 0, sizeof(MboxHeaderContext));
+	md5_init(&ctx->md5);
+}
+
+static MailFlags mbox_get_status_flags(const char *value, unsigned int len)
 {
 	MailFlags flags;
 	unsigned int i;
 
 	flags = 0;
-	if ((name_len == 6 && strncasecmp(name, "Status", 6) == 0) ||
-	    (name_len == 8 && strncasecmp(name, "X-Status", 8) == 0)) {
-		    for (i = 0; i < value_len; i++) {
-			    switch (value[i]) {
-			    case 'A':
-				    flags |= MAIL_ANSWERED;
-				    break;
-			    case 'F':
-				    flags |= MAIL_FLAGGED;
-				    break;
-			    case 'R':
-				    flags |= MAIL_SEEN;
-				    break;
-			    case 'D':
-				    flags |= MAIL_DELETED;
-				    break;
-			    }
-		    }
+	for (i = 0; i < len; i++) {
+		switch (value[i]) {
+		case 'A':
+			flags |= MAIL_ANSWERED;
+			break;
+		case 'F':
+			flags |= MAIL_FLAGGED;
+			break;
+		case 'R':
+			flags |= MAIL_SEEN;
+			break;
+		case 'D':
+			flags |= MAIL_DELETED;
+			break;
+		}
 	}
 
 	return flags;
 }
 
+void mbox_header_func(MessagePart *part __attr_unused__,
+		      const char *name, unsigned int name_len,
+		      const char *value, unsigned int value_len,
+		      void *context)
+{
+	MboxHeaderContext *ctx = context;
+	int fixed = FALSE;
+
+	/* Pretty much copy&pasted from popa3d by Solar Designer */
+	switch (*name) {
+	case 'R':
+	case 'r':
+		if (!ctx->received && name_len == 8 &&
+		    strncasecmp(name, "Received", 8) == 0) {
+			ctx->received = TRUE;
+			fixed = TRUE;
+		}
+		break;
+
+	case 'D':
+	case 'd':
+		if (name_len == 12)
+			fixed = strncasecmp(name, "Delivered-To", 12) == 0;
+		else if (name_len == 4) {
+			/* Received-header contains date too,
+			   and more trusted one */
+			fixed = !ctx->received &&
+				strncasecmp(name, "Date", 4) == 0;
+		}
+		break;
+
+	case 'M':
+	case 'm':
+		if (name_len == 10) {
+			/* Received-header contains unique ID too,
+			   and more trusted one */
+			fixed = !ctx->received &&
+				strncasecmp(name, "Message-ID", 10) == 0;
+		}
+		break;
+
+	case 'S':
+	case 's':
+		if (name_len == 6 && strncasecmp(name, "Status", 6) == 0) {
+			/* update message flags */
+			ctx->flags |= mbox_get_status_flags(value, value_len);
+		}
+		break;
+
+	case 'X':
+	case 'x':
+		/* Let the local delivery agent help generate unique ID's but
+		   don't blindly trust this header alone as it could just as
+		   easily come from the remote. */
+		if (name_len == 13)
+			fixed = strncasecmp(name, "X-Delivery-ID:", 13);
+		else if (name_len == 8 &&
+			 strncasecmp(name, "X-Status", 8) == 0) {
+			/* update message flags */
+			ctx->flags |= mbox_get_status_flags(value, value_len);
+		}
+		break;
+	}
+
+	if (fixed)
+		md5_update(&ctx->md5, value, value_len);
+}
+
+int mbox_skip_crlf(IOBuffer *inbuf)
+{
+	unsigned char *data;
+	unsigned int size;
+
+	while (io_buffer_read_data(inbuf, &data, &size, 1) >= 0) {
+		if (size > 0) {
+			if (data[0] == '\n') {
+				io_buffer_skip(inbuf, 1);
+				return TRUE;
+			}
+			if (data[0] != '\r')
+				return FALSE;
+
+			if (size > 1) {
+				if (data[1] != '\n')
+					return FALSE;
+
+				io_buffer_skip(inbuf, 2);
+				return TRUE;
+			}
+		}
+	}
+
+	/* end of file */
+	return TRUE;
+}
+
 MailIndex *mbox_index_alloc(const char *dir, const char *mbox_path)
 {
 	MailIndex *index;
--- a/src/lib-index/mbox/mbox-index.h	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-index.h	Sat Aug 24 05:04:45 2002 +0300
@@ -1,20 +1,32 @@
 #ifndef __MBOX_INDEX_H
 #define __MBOX_INDEX_H
 
+#include "md5.h"
 #include "mail-index.h"
 
+typedef struct {
+	MailFlags flags;
+	MD5Context md5;
+	int received;
+} MboxHeaderContext;
+
 MailIndex *mbox_index_alloc(const char *dir, const char *mbox_path);
 
-MailFlags mbox_header_get_flags(const char *name, unsigned int name_len,
-				const char *value, unsigned int value_len);
+void mbox_header_init_context(MboxHeaderContext *ctx);
+void mbox_header_func(MessagePart *part __attr_unused__,
+		      const char *name, unsigned int name_len,
+		      const char *value, unsigned int value_len,
+		      void *context);
+int mbox_skip_crlf(IOBuffer *inbuf);
 
 int mbox_index_rebuild(MailIndex *index);
 int mbox_index_sync(MailIndex *index);
 int mbox_index_fsck(MailIndex *index);
 IOBuffer *mbox_open_mail(MailIndex *index, MailIndexRecord *rec);
 
-int mbox_index_append(MailIndex *index, int fd, const char *path);
-int mbox_index_append_mmaped(MailIndex *index, const char *data,
-			     size_t data_size, off_t start_offset);
+int mbox_index_append(MailIndex *index, IOBuffer *inbuf);
+
+time_t mbox_from_parse_date(const char *msg, unsigned int size);
+const char *mbox_from_create(const char *sender, time_t time);
 
 #endif
--- a/src/lib-index/mbox/mbox-open.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-open.c	Sat Aug 24 05:04:45 2002 +0300
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "iobuffer.h"
+#include "hex-binary.h"
 #include "mbox-index.h"
 #include "mail-index-util.h"
 
@@ -13,8 +14,8 @@
 {
 	const char *location;
 	off_t pos, offset, stop_offset;
-	char buf[5];
-	int fd, ret, ok;
+	char buf[7], *p;
+	int fd, ret, failed;
 
 	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
 
@@ -27,8 +28,16 @@
 		return NULL;
 	}
 
-	/* location = offset */
-	offset = (off_t)strtoul(location, NULL, 10);
+	/* location = offset in hex */
+	if (strlen(location) != sizeof(offset)*2 ||
+	    hex_to_binary(location, (unsigned char *) &offset) <= 0) {
+                INDEX_MARK_CORRUPTED(index);
+		index_set_error(index, "Corrupted index file %s: "
+				"Invalid location field for record %u",
+				index->filepath, rec->uid);
+		return NULL;
+	}
+
 	stop_offset = offset + rec->header_size + rec->body_size;
 
 	fd = open(index->mbox_path, O_RDONLY);
@@ -46,21 +55,30 @@
 		return NULL;
 	}
 
-	ok = FALSE;
+	failed = TRUE;
 	if (pos == offset) {
 		/* make sure message size is valid */
 		if (lseek(fd, stop_offset, SEEK_SET) == stop_offset) {
 			/* and check that we end with either EOF or to
 			   beginning of next message */
-			ret = read(fd, buf, 5);
+			ret = read(fd, buf, 7);
 			if (ret == 0)
-				ok = TRUE; /* end of file */
-			else if (ret == 5 && strncmp(buf, "From ", 5) == 0)
-				ok = TRUE;
+				failed = FALSE; /* end of file */
+			else if (ret >= 6) {
+				/* "[\r]\nFrom " expected */
+				if (buf[0] != '\r')
+					p = buf;
+				else {
+					p = buf+1;
+					ret--;
+				}
+				if (ret >= 6 && strncmp(p, "\nFrom ", 6) == 0)
+					failed = FALSE;
+			}
 		}
 	}
 
-	if (ok) {
+	if (!failed) {
 		if (lseek(fd, offset, SEEK_SET) == offset) {
 			/* everything ok */
 			return io_buffer_create_mmap(fd, default_pool,
@@ -74,6 +92,9 @@
 	} else {
 		/* file has been updated, rescan it */
 		index->set_flags |= MAIL_INDEX_FLAG_FSCK;
+
+		index_set_error(index, "mbox file %s was modified "
+				"unexpectedly, fscking", index->mbox_path);
 	}
 
 	(void)close(fd);
--- a/src/lib-index/mbox/mbox-rebuild.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-rebuild.c	Sat Aug 24 05:04:45 2002 +0300
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "iobuffer.h"
 #include "mbox-index.h"
 #include "mbox-lock.h"
 #include "mail-index-data.h"
@@ -14,6 +15,7 @@
 
 int mbox_index_rebuild(MailIndex *index)
 {
+	IOBuffer *inbuf;
 	struct stat st;
 	int fd;
 
@@ -25,14 +27,17 @@
 	/* reset the header */
 	mail_index_init_header(index->header);
 
-	/* we require Message-ID to be cached */
-	index->header->cache_fields |= FIELD_TYPE_MESSAGEID;
+	/* we require MD5 to be cached */
+	index->header->cache_fields |= FIELD_TYPE_MD5;
 
 	/* update indexid */
 	index->indexid = index->header->indexid;
 
-	if (msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) == -1)
+	if (msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) == -1) {
+		index_set_error(index, "msync() failed for index file %s: %m",
+				index->filepath);
 		return FALSE;
+	}
 
 	/* truncate the file first, so it won't contain
 	   any invalid data even if we crash */
@@ -61,7 +66,9 @@
 		return FALSE;
 	}
 
-	if (!mbox_index_append(index, fd, index->mbox_path)) {
+	inbuf = io_buffer_create_mmap(fd, default_pool,
+				      MAIL_MMAP_BLOCK_SIZE, -1);
+	if (!mbox_index_append(index, inbuf)) {
 		(void)mbox_unlock(index, index->mbox_path, fd);
 		(void)close(fd);
 		return FALSE;
@@ -69,6 +76,7 @@
 
 	(void)mbox_unlock(index, index->mbox_path, fd);
 	(void)close(fd);
+	io_buffer_destroy(inbuf);
 
 	/* update sync stamp */
 	if (stat(index->mbox_path, &st) == -1) {
--- a/src/lib-index/mbox/mbox-sync.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-index/mbox/mbox-sync.c	Sat Aug 24 05:04:45 2002 +0300
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "iobuffer.h"
 #include "mbox-index.h"
 #include "mail-index-util.h"
 
@@ -9,17 +10,18 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
-static size_t get_indexed_mbox_size(MailIndex *index)
+static off_t get_indexed_mbox_size(MailIndex *index)
 {
 	MailIndexRecord *rec, *prev;
 	const char *location;
-	size_t size;
+	unsigned long size;
 
 	if (index->lock_type == MAIL_LOCK_UNLOCK) {
 		if (!mail_index_set_lock(index, MAIL_LOCK_SHARED))
 			return 0;
 	}
 
+	/* get the last record */
 	rec = index->header->messages_count == 0 ? NULL :
 		index->lookup(index, index->header->messages_count);
 	if (rec == NULL) {
@@ -34,6 +36,8 @@
 
 	size = 0;
 	if (rec != NULL) {
+		/* get the offset + size of last message, which tells the
+		   last known mbox file size */
 		location = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
 		if (location == NULL) {
 			INDEX_MARK_CORRUPTED(index);
@@ -48,11 +52,12 @@
 
 	if (index->lock_type == MAIL_LOCK_SHARED)
 		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
-	return size;
+	return (off_t)size;
 }
 
 static int mbox_check_new_mail(MailIndex *index)
 {
+	IOBuffer *inbuf;
 	off_t pos;
 	int fd, ret;
 
@@ -78,8 +83,11 @@
 	}
 
 	/* add the new data */
-	ret = mbox_index_append(index, fd, index->mbox_path);
+	inbuf = io_buffer_create_mmap(fd, default_pool,
+				      MAIL_MMAP_BLOCK_SIZE, -1);
+	ret = mbox_index_append(index, inbuf);
 	(void)close(fd);
+	io_buffer_destroy(inbuf);
 
 	if (index->set_flags & MAIL_INDEX_FLAG_FSCK) {
 		/* it wasn't just new mail, reread the mbox */
--- a/src/lib-storage/index/index-copy.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-storage/index/index-copy.c	Sat Aug 24 05:04:45 2002 +0300
@@ -26,7 +26,7 @@
 	/* save it in destination mailbox */
 	failed = !cd->dest->save(cd->dest, rec->msg_flags,
 				 cd->custom_flags, rec->internal_date,
-				 inbuf, inbuf->stop_offset - inbuf->offset);
+				 inbuf, inbuf->size);
 	(void)close(inbuf->fd);
 	io_buffer_destroy(inbuf);
 	return !failed;
--- a/src/lib-storage/index/maildir/maildir-storage.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sat Aug 24 05:04:45 2002 +0300
@@ -18,7 +18,7 @@
 
 static const char *maildirs[] = { "cur", "new", "tmp", NULL  };
 
-static MailStorage *maildir_create(const char *data)
+static MailStorage *maildir_create(const char *data, const char *user)
 {
 	MailStorage *storage;
 	const char *home, *path;
@@ -46,12 +46,14 @@
 	memcpy(storage, &maildir_storage, sizeof(MailStorage));
 
 	storage->dir = i_strdup(data);
+	storage->user = i_strdup(user);
 	return storage;
 }
 
 static void maildir_free(MailStorage *storage)
 {
 	i_free(storage->dir);
+	i_free(storage->user);
 	i_free(storage);
 }
 
@@ -357,6 +359,7 @@
 	mail_storage_get_last_error,
 
 	NULL,
+	NULL,
 	NULL
 };
 
--- a/src/lib-storage/index/mbox/mbox-save.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-storage/index/mbox/mbox-save.c	Sat Aug 24 05:04:45 2002 +0300
@@ -10,6 +10,38 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <netdb.h>
+
+static char my_hostdomain[256] = "";
+
+static int write_from_line(MailStorage *storage, int fd, time_t internal_date)
+{
+	const char *sender, *line, *name;
+	size_t len;
+
+	if (*my_hostdomain == '\0') {
+		struct hostent *hent;
+
+		hostpid_init();
+		hent = gethostbyname(my_hostname);
+
+		name = hent != NULL ? hent->h_name : NULL;
+		if (name == NULL) {
+			/* failed, use just the hostname */
+			name = my_hostname;
+		}
+
+		strncpy(my_hostdomain, name, 255);
+		my_hostdomain[255] = '\0';
+	}
+
+	sender = t_strconcat(storage->user, "@", my_hostdomain, NULL);
+
+	line = mbox_from_create(sender, internal_date);
+	len = strlen(line);
+
+	return (size_t)write(fd, line, len) == len;
+}
 
 int mbox_storage_save(Mailbox *box, MailFlags flags, const char *custom_flags[],
 		      time_t internal_date, IOBuffer *data, size_t data_size)
@@ -47,14 +79,15 @@
 					  "lseek() failed for mbox file %s: %m",
 					  ibox->index->mbox_path);
 		failed = TRUE;
-	}
-
-	if (!failed && !index_storage_save_into_fd(box->storage, fd,
-						   ibox->index->mbox_path,
-						   data, data_size)) {
-		/* failed, truncate file back to original size */
-		(void)ftruncate(fd, pos);
-		failed = TRUE;
+	} else {
+		if (!write_from_line(box->storage, fd, internal_date) ||
+		    !index_storage_save_into_fd(box->storage, fd,
+						ibox->index->mbox_path,
+						data, data_size)) {
+			/* failed, truncate file back to original size */
+			(void)ftruncate(fd, pos);
+			failed = TRUE;
+		}
 	}
 
 	(void)mbox_unlock(ibox->index, ibox->index->mbox_path, fd);
--- a/src/lib-storage/index/mbox/mbox-storage.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Sat Aug 24 05:04:45 2002 +0300
@@ -40,7 +40,7 @@
 	return FALSE;
 }
 
-static MailStorage *mbox_create(const char *data)
+static MailStorage *mbox_create(const char *data, const char *user)
 {
 	MailStorage *storage;
 	const char *home, *path;
@@ -73,12 +73,14 @@
 	memcpy(storage, &mbox_storage, sizeof(MailStorage));
 
 	storage->dir = i_strdup(data);
+	storage->user = i_strdup(user);
 	return storage;
 }
 
 static void mbox_free(MailStorage *storage)
 {
 	i_free(storage->dir);
+	i_free(storage->user);
 	i_free(storage);
 }
 
@@ -346,6 +348,7 @@
 	mail_storage_get_last_error,
 
 	NULL,
+	NULL,
 	NULL
 };
 
--- a/src/lib-storage/mail-storage.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-storage/mail-storage.c	Sat Aug 24 05:04:45 2002 +0300
@@ -49,7 +49,8 @@
 	}
 }
 
-MailStorage *mail_storage_create(const char *name, const char *data)
+MailStorage *mail_storage_create(const char *name, const char *data,
+				 const char *user)
 {
 	MailStorageList *list;
 
@@ -57,19 +58,19 @@
 
 	for (list = storages; list != NULL; list = list->next) {
 		if (strcasecmp(list->storage->name, name) == 0)
-			return list->storage->create(data);
+			return list->storage->create(data, user);
 	}
 
 	return NULL;
 }
 
-MailStorage *mail_storage_create_default(void)
+MailStorage *mail_storage_create_default(const char *user)
 {
 	MailStorageList *list;
 	MailStorage *storage;
 
 	for (list = storages; list != NULL; list = list->next) {
-		storage = list->storage->create(NULL);
+		storage = list->storage->create(NULL, user);
 		if (storage != NULL)
 			return storage;
 	}
@@ -89,13 +90,13 @@
 	return NULL;
 }
 
-MailStorage *mail_storage_create_with_data(const char *data)
+MailStorage *mail_storage_create_with_data(const char *data, const char *user)
 {
 	MailStorage *storage;
 	const char *p, *name;
 
 	if (data == NULL || *data == '\0')
-		return mail_storage_create_default();
+		return mail_storage_create_default(user);
 
 	/* check if we're in the form of mailformat:data
 	   (eg. maildir:Maildir) */
@@ -104,11 +105,11 @@
 
 	if (*p == ':') {
 		name = t_strdup_until(data, p);
-		storage = mail_storage_create(name, p+1);
+		storage = mail_storage_create(name, p+1, user);
 	} else {
 		storage = mail_storage_autodetect(data);
 		if (storage != NULL)
-			storage = storage->create(data);
+			storage = storage->create(data, user);
 	}
 
 	return storage;
--- a/src/lib-storage/mail-storage.h	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib-storage/mail-storage.h	Sat Aug 24 05:04:45 2002 +0300
@@ -60,7 +60,7 @@
 	char hierarchy_sep;
 
 	/* Create new instance */
-	MailStorage *(*create)(const char *data);
+	MailStorage *(*create)(const char *data, const char *user);
 
 	/* Free this instance */
 	void (*free)(MailStorage *storage);
@@ -109,6 +109,7 @@
 
 /* private: */
 	char *dir; /* root directory */
+	char *user; /* name of user accessing the storage */
 	char *error;
 };
 
@@ -223,11 +224,12 @@
 /* Create a new instance of registered mail storage class with given
    storage-specific data. If data is NULL, it tries to use defaults.
    May return NULL if anything fails. */
-MailStorage *mail_storage_create(const char *name, const char *data);
+MailStorage *mail_storage_create(const char *name, const char *data,
+				 const char *user);
 void mail_storage_destroy(MailStorage *storage);
 
-MailStorage *mail_storage_create_default(void);
-MailStorage *mail_storage_create_with_data(const char *data);
+MailStorage *mail_storage_create_default(const char *user);
+MailStorage *mail_storage_create_with_data(const char *data, const char *user);
 
 /* Set error message in storage. Critical errors are logged with i_error(),
    but user sees only "internal error" message. */
--- a/src/lib/iobuffer.c	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib/iobuffer.c	Sat Aug 24 05:04:45 2002 +0300
@@ -50,7 +50,7 @@
 	buf->fd = fd;
 	buf->pool = pool;
 	buf->priority = priority;
-	buf->max_size = max_buffer_size;
+	buf->max_buffer_size = max_buffer_size;
 	return buf;
 }
 
@@ -65,7 +65,7 @@
 }
 
 IOBuffer *io_buffer_create_mmap(int fd, Pool pool, unsigned int block_size,
-				off_t stop_offset)
+				off_t size)
 {
 	IOBuffer *buf;
 
@@ -83,24 +83,20 @@
 	}
 
 	buf = io_buffer_create_file(fd, pool, block_size);
-	buf->stop_offset = stop_offset;
 	buf->mmaped = TRUE;
 	buf->receive = TRUE;
 
 	/* set offsets */
 	buf->start_offset = lseek(fd, 0, SEEK_CUR);
-	buf->stop_offset = stop_offset > 0 ? stop_offset :
-		lseek(fd, 0, SEEK_END);
+	buf->size = size > 0 ? size :
+		lseek(fd, 0, SEEK_END) - buf->start_offset;
 
-	if (buf->start_offset == -1 || buf->stop_offset == -1) {
+	if (buf->start_offset < 0 || buf->size < 0) {
 		i_error("io_buffer_create_mmap(): lseek() failed: %m");
-		buf->start_offset = buf->stop_offset = 0;
+		buf->start_offset = buf->size = 0;
 	}
 
-	/* fix offset alignment */
-	buf->mmap_offset = buf->start_offset & ~mmap_pagemask;
-	buf->skip = buf->mmap_offset & mmap_pagemask;
-
+	buf->skip = buf->pos = buf->start_offset;
 	return buf;
 }
 
@@ -115,7 +111,7 @@
 		if (!buf->mmaped)
 			p_free(buf->pool, buf->buffer);
 		else
-			(void)munmap(buf->buffer, buf->size);
+			(void)munmap(buf->buffer, buf->buffer_size);
 	}
         p_free(buf->pool, buf);
 }
@@ -134,9 +130,9 @@
 	buf->last_cr = FALSE;
 
 	if (buf->mmaped && buf->buffer != NULL) {
-		(void)munmap(buf->buffer, buf->size);
+		(void)munmap(buf->buffer, buf->buffer_size);
 		buf->buffer = NULL;
-		buf->size = 0;
+		buf->buffer_size = 0;
 	}
 
 	buf->mmap_offset = buf->offset = 0;
@@ -155,9 +151,9 @@
 	newbuf->pool = pool;
 
 	if (!newbuf->mmaped) {
-		newbuf->buffer = p_malloc(pool, buf->size);
+		newbuf->buffer = p_malloc(pool, buf->buffer_size);
 		memcpy(newbuf->buffer, buf->buffer + buf->skip,
-		       buf->size - buf->skip);
+		       buf->buffer_size - buf->skip);
 
 		newbuf->cr_lookup_pos -= newbuf->skip;
 		newbuf->pos -= newbuf->skip;
@@ -174,7 +170,7 @@
 {
 	i_assert(!buf->mmaped);
 
-	buf->max_size = max_size;
+	buf->max_buffer_size = max_size;
 }
 
 void io_buffer_set_send_blocking(IOBuffer *buf, unsigned int max_size,
@@ -188,7 +184,7 @@
 	buf->timeout_func = timeout_func;
 	buf->timeout_context = context;
 	buf->blocking = max_size > 0;
-	buf->max_size = max_size;
+	buf->max_buffer_size = max_size;
 }
 
 static int my_write(int fd, const void *buf, unsigned int size)
@@ -373,17 +369,18 @@
 {
 	i_assert(!buf->mmaped);
 
-	buf->size = buf->pos+size;
-	buf->size = buf->size <= IO_BUFFER_MIN_SIZE ? IO_BUFFER_MIN_SIZE :
-		nearest_power(buf->size);
+	buf->buffer_size = buf->pos+size;
+	buf->buffer_size =
+		buf->buffer_size <= IO_BUFFER_MIN_SIZE ? IO_BUFFER_MIN_SIZE :
+		nearest_power(buf->buffer_size);
 
-	if (buf->max_size > 0 && buf->size > buf->max_size)
-		buf->size = buf->max_size;
+	if (buf->max_buffer_size > 0 && buf->buffer_size > buf->max_buffer_size)
+		buf->buffer_size = buf->max_buffer_size;
 
-	buf->buffer = p_realloc(buf->pool, buf->buffer, buf->size);
+	buf->buffer = p_realloc(buf->pool, buf->buffer, buf->buffer_size);
 	if (buf->buffer == NULL) {
 		/* pool limit exceeded */
-		buf->pos = buf->size = 0;
+		buf->pos = buf->buffer_size = 0;
 	}
 }
 
@@ -456,7 +453,7 @@
 	int ret;
 
 	ret = sendfile(ctx->outbuf->fd, ctx->inbuf->fd,
-		       &ctx->inbuf->mmap_offset, ctx->size);
+		       &ctx->inbuf->offset, ctx->size);
 	if (ret < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			ctx->outbuf->closed = TRUE;
@@ -598,44 +595,43 @@
 
 int io_buffer_read_mmaped(IOBuffer *buf, unsigned int size)
 {
-	unsigned int aligned_skip;
+	off_t stop_offset, aligned_skip;
 
-	if (buf->stop_offset - buf->mmap_offset <= (off_t)buf->size) {
+	stop_offset = buf->size + buf->start_offset;
+	if (stop_offset - buf->mmap_offset <= (off_t)buf->buffer_size) {
 		/* end of file is already mapped */
 		return -1;
 	}
 
-	if (buf->pos != 0) {
-		aligned_skip = buf->skip & ~mmap_pagemask;
-		if (aligned_skip == 0 && buf->buffer != NULL) {
-			/* didn't skip enough bytes */
-			return -2;
-		}
-
-		buf->skip -= aligned_skip;
-		buf->mmap_offset += aligned_skip;
+	aligned_skip = buf->skip & ~mmap_pagemask;
+	if (aligned_skip == 0 && buf->buffer != NULL) {
+		/* didn't skip enough bytes */
+		return -2;
 	}
 
+	buf->skip -= aligned_skip;
+	buf->mmap_offset += aligned_skip;
+
 	if (buf->buffer != NULL)
-		(void)munmap(buf->buffer, buf->size);
+		(void)munmap(buf->buffer, buf->buffer_size);
 
-	buf->size = buf->stop_offset - buf->mmap_offset < (off_t)buf->max_size ?
-		buf->stop_offset - buf->mmap_offset : buf->max_size;
+	buf->buffer_size = stop_offset - buf->mmap_offset;
+	if (buf->buffer_size > buf->max_buffer_size)
+		buf->buffer_size = buf->max_buffer_size;
+	if (buf->buffer_size > size)
+		buf->buffer_size = size;
 
-	if (buf->size > size)
-		buf->size = size;
-
-	buf->buffer = mmap(NULL, buf->size, PROT_READ, MAP_PRIVATE,
+	buf->buffer = mmap(NULL, buf->buffer_size, PROT_READ, MAP_PRIVATE,
 			   buf->fd, buf->mmap_offset);
 	if (buf->buffer == MAP_FAILED) {
 		i_error("io_buffer_read_mmaped(): mmap() failed: %m");
 		return -1;
 	}
 
-	(void)madvise(buf->buffer, buf->size, MADV_SEQUENTIAL);
+	(void)madvise(buf->buffer, buf->buffer_size, MADV_SEQUENTIAL);
 
-	buf->pos = buf->size;
-	return buf->size;
+	buf->pos = buf->buffer_size;
+	return buf->buffer_size;
 }
 
 int io_buffer_read_max(IOBuffer *buf, unsigned int size)
@@ -652,29 +648,30 @@
 	if (buf->mmaped)
 		return io_buffer_read_mmaped(buf, size);
 
-	if (buf->pos == buf->size) {
+	if (buf->pos == buf->buffer_size) {
 		if (buf->skip > 0) {
 			/* remove the unused bytes from beginning of buffer */
                         io_buffer_compress(buf);
-		} else if (buf->max_size == 0 || buf->size < buf->max_size) {
+		} else if (buf->max_buffer_size == 0 ||
+			   buf->buffer_size < buf->max_buffer_size) {
 			/* buffer is full - grow it */
 			buffer_alloc_more(buf, IO_BUFFER_MIN_SIZE);
 		}
 
-		if (buf->pos == buf->size)
+		if (buf->pos == buf->buffer_size)
                         return -2; /* buffer full */
 	}
 
         /* fill the buffer */
-	if (buf->size-buf->pos < size)
-		size = buf->size - buf->pos;
+	if (buf->buffer_size-buf->pos < size)
+		size = buf->buffer_size - buf->pos;
 
 	if (!buf->file) {
 		ret = net_receive(buf->fd, buf->buffer + buf->pos,
-				  buf->size - buf->pos);
+				  buf->buffer_size - buf->pos);
 	} else {
                 ret = read(buf->fd, buf->buffer + buf->pos,
-			   buf->size - buf->pos);
+			   buf->buffer_size - buf->pos);
 		if (ret == 0)
 			ret = -1; /* EOF */
 		else if (ret < 0 && (errno == EINTR || errno == EAGAIN))
@@ -707,24 +704,17 @@
 	}
 
 	if (buf->mmaped) {
-		if (buf->stop_offset - buf->mmap_offset <= (off_t)size) {
-			/* end of file */
-			buf->mmap_offset = buf->stop_offset;
-			buf->size = 0;
-			return;
-		}
-
 		/* these point outside mmap now, next io_buffer_read_mmaped()
 		   will fix them */
 		buf->skip += size;
 		buf->pos = buf->skip;
 	} else {
-		if (buf->size == 0)
+		if (buf->buffer_size == 0)
 			buffer_alloc_more(buf, IO_BUFFER_MIN_SIZE);
 
 		size -= buf->skip;
-		while (size > buf->size) {
-			ret = io_buffer_read_max(buf, buf->size);
+		while (size > buf->buffer_size) {
+			ret = io_buffer_read_max(buf, buf->buffer_size);
 			if (ret <= 0)
 				break;
 
@@ -747,7 +737,7 @@
 
 		/* then set the wanted position, next read will
 		   pick up from there */
-		buf->mmap_offset = buf->start_offset;
+		buf->offset = buf->start_offset;
 		buf->pos = buf->skip = offset;
 	} else {
 		real_offset = buf->start_offset + offset;
@@ -844,18 +834,19 @@
 	buf->transmit = TRUE;
 
 	/* make sure we have enough space in buffer */
-	if (buf->size - buf->pos < size && buf->skip > 0) {
+	if (buf->buffer_size - buf->pos < size && buf->skip > 0) {
 		/* remove the unused bytes from beginning of buffer */
 		io_buffer_compress(buf);
 	}
 
-	if (buf->size - buf->pos < size &&
-	    (buf->max_size == 0 || size <= buf->max_size - buf->pos)) {
+	if (buf->buffer_size - buf->pos < size &&
+	    (buf->max_buffer_size == 0 ||
+	     size <= buf->max_buffer_size - buf->pos)) {
 		/* allocate more space */
                 buffer_alloc_more(buf, size);
 	}
 
-	if (buf->size - buf->pos < size)
+	if (buf->buffer_size - buf->pos < size)
                 return NULL;
 
         return buf->buffer + buf->pos;
@@ -903,9 +894,9 @@
 
 	io_buffer_reset(buf);
 
-	if (buf->size < size) {
+	if (buf->buffer_size < size) {
 		buffer_alloc_more(buf, size);
-		if (buf->size < size)
+		if (buf->buffer_size < size)
                         return -2;
 	}
 
--- a/src/lib/iobuffer.h	Fri Aug 23 19:21:36 2002 +0300
+++ b/src/lib/iobuffer.h	Sat Aug 24 05:04:45 2002 +0300
@@ -10,10 +10,8 @@
 struct _IOBuffer {
 	int fd;
 
-	unsigned int pos, skip;
-	unsigned int size, max_size;
-	off_t start_offset, stop_offset;
-	off_t offset; /* virtual offset, 0 = start_offset */
+	off_t start_offset;
+	off_t offset, size; /* virtual offset, 0 = start_offset */
 
 /* private: */
 	Pool pool;
@@ -29,7 +27,10 @@
 
 	unsigned char *buffer;
         unsigned int cr_lookup_pos; /* used only when reading a line */
+
 	off_t mmap_offset;
+	unsigned int pos, skip;
+	unsigned int buffer_size, max_buffer_size;
 
 	unsigned int file:1; /* reading/writing a file */
 	unsigned int mmaped:1; /* reading a file with mmap() */
@@ -52,7 +53,7 @@
 /* Read the file by mmap()ing it in blocks. stop_offset specifies where to
    stop reading, or 0 to end of file. */
 IOBuffer *io_buffer_create_mmap(int fd, Pool pool, unsigned int block_size,
-				off_t stop_offset);
+				off_t size);
 /* Destroy a buffer. */
 void io_buffer_destroy(IOBuffer *buf);
 /* Mark the buffer closed. Any sends/reads after this will return -1.