changeset 1914:1f156d653f4a HEAD

removed out of the way of new index code
author Timo Sirainen <tss@iki.fi>
date Tue, 27 Apr 2004 23:14:15 +0300
parents be667b9f4605
children 79790750c349
files src/lib-index/mail-cache.c src/lib-index/mail-cache.h src/lib-index/mail-custom-flags.c src/lib-index/mail-custom-flags.h src/lib-index/mail-index-file.c src/lib-index/mail-index-fsck.c src/lib-index/mail-index-open.c src/lib-index/mail-index-rebuild.c src/lib-index/mail-index-util.c src/lib-index/mail-index-util.h src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-index/mail-modifylog.c src/lib-index/mail-modifylog.h src/lib-index/maildir/maildir-build.c src/lib-index/maildir/maildir-clean.c src/lib-index/maildir/maildir-expunge.c src/lib-index/maildir/maildir-index.c src/lib-index/maildir/maildir-index.h src/lib-index/maildir/maildir-open.c src/lib-index/maildir/maildir-sync.c src/lib-index/maildir/maildir-uidlist.c src/lib-index/maildir/maildir-uidlist.h src/lib-index/maildir/maildir-update-flags.c src/lib-index/mbox/istream-mbox.c src/lib-index/mbox/mbox-append.c src/lib-index/mbox/mbox-from.c src/lib-index/mbox/mbox-index.c src/lib-index/mbox/mbox-index.h src/lib-index/mbox/mbox-lock.c src/lib-index/mbox/mbox-lock.h src/lib-index/mbox/mbox-open.c src/lib-index/mbox/mbox-rewrite.c src/lib-index/mbox/mbox-sync-full.c src/lib-index/mbox/mbox-sync.c
diffstat 35 files changed, 0 insertions(+), 12089 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-cache.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1940 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "buffer.h"
-#include "byteorder.h"
-#include "file-lock.h"
-#include "file-set-size.h"
-#include "ioloop.h"
-#include "mmap-util.h"
-#include "write-full.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <stddef.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-/* Never compress the file if it's smaller than this */
-#define COMPRESS_MIN_SIZE (1024*50)
-
-/* Compress the file when deleted space reaches n% of total size */
-#define COMPRESS_PERCENTAGE 20
-
-/* Compress the file when n% of rows contain continued rows.
-   200% means that there's 2 continued rows per record. */
-#define COMPRESS_CONTINUED_PERCENTAGE 200
-
-/* Initial size for the file */
-#define MAIL_CACHE_INITIAL_SIZE (sizeof(struct mail_cache_header) + 10240)
-
-/* When more space is needed, grow the file n% larger than the previous size */
-#define MAIL_CACHE_GROW_PERCENTAGE 10
-
-#define MAIL_CACHE_LOCK_TIMEOUT 120
-#define MAIL_CACHE_LOCK_CHANGE_TIMEOUT 60
-#define MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT (5*60)
-
-#define CACHE_RECORD(cache, offset) \
-	((struct mail_cache_record *) ((char *) (cache)->mmap_base + offset))
-
-struct mail_cache_header {
-	uint32_t indexid;
-	uint32_t sync_id;
-
-	uint32_t continued_record_count;
-
-	uint32_t used_file_size;
-	uint32_t deleted_space;
-
-	uint32_t used_fields; /* enum mail_cache_field */
-
-	uint32_t field_usage_start; /* time_t */
-	uint32_t field_usage_counts[32];
-
-	uint32_t header_offsets[MAIL_CACHE_HEADERS_COUNT];
-};
-
-struct mail_cache_record {
-	uint32_t fields; /* enum mail_cache_field */
-	uint32_t next_offset;
-	uint32_t size; /* full record size, including this header */
-};
-
-struct mail_cache {
-	struct mail_index *index;
-
-	char *filepath;
-	int fd;
-
-	void *mmap_base;
-	size_t mmap_length;
-	uint32_t used_file_size;
-	uint32_t sync_id;
-
-	struct mail_cache_header *header;
-
-	pool_t split_header_pool;
-	uint32_t split_offsets[MAIL_CACHE_HEADERS_COUNT];
-	const char *const *split_headers[MAIL_CACHE_HEADERS_COUNT];
-
-	enum mail_cache_field default_cache_fields;
-	enum mail_cache_field never_cache_fields;
-
-        struct mail_cache_transaction_ctx *trans_ctx;
-	unsigned int locks;
-
-	unsigned int anon_mmap:1;
-	unsigned int mmap_refresh:1;
-	unsigned int silent:1;
-};
-
-struct mail_cache_transaction_ctx {
-	struct mail_cache *cache;
-
-	unsigned int next_unused_header_lowwater;
-
-	unsigned int last_idx;
-	struct mail_cache_record cache_rec;
-	buffer_t *cache_data;
-
-	unsigned int first_uid, last_uid, prev_uid;
-	enum mail_cache_field prev_fields;
-	buffer_t *index_marks, *cache_marks;
-};
-
-unsigned int mail_cache_field_sizes[32] = {
-	sizeof(enum mail_index_record_flag),
-	sizeof(uoff_t),
-	16,
-	sizeof(struct mail_sent_date),
-	sizeof(time_t),
-	sizeof(uoff_t),
-	sizeof(uoff_t),
-
-	0, 0, 0, 0, 0,
-
-	/* variable sized */
-	(unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
-	(unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
-	(unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
-	(unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
-	(unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1
-};
-
-enum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT] = {
-	MAIL_CACHE_HEADERS1,
-	MAIL_CACHE_HEADERS2,
-	MAIL_CACHE_HEADERS3,
-	MAIL_CACHE_HEADERS4
-};
-
-static const unsigned char *null4[] = { 0, 0, 0, 0 };
-
-static const char *
-mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx);
-static int mail_cache_write(struct mail_cache_transaction_ctx *ctx);
-static struct mail_cache_record *
-mail_cache_lookup(struct mail_cache *cache,
-		  const struct mail_index_record *rec,
-		  enum mail_cache_field fields);
-
-static uint32_t uint32_to_offset(uint32_t offset)
-{
-	unsigned char buf[4];
-
-	i_assert(offset < 0x40000000);
-	i_assert((offset & 3) == 0);
-
-	offset >>= 2;
-	buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
-	buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
-	buf[2] = 0x80 | ((offset & 0x00003f80) >> 7);
-	buf[3] = 0x80 |  (offset & 0x0000007f);
-	return *((uint32_t *) buf);
-}
-
-static uint32_t offset_to_uint32(uint32_t offset)
-{
-	const unsigned char *buf = (const unsigned char *) &offset;
-
-	if ((offset & 0x80808080) != 0x80808080)
-		return 0;
-
-	return (((uint32_t)buf[3] & 0x7f) << 2) |
-		(((uint32_t)buf[2] & 0x7f) << 9) |
-		(((uint32_t)buf[1] & 0x7f) << 16) |
-		(((uint32_t)buf[0] & 0x7f) << 23);
-}
-
-static int mail_cache_set_syscall_error(struct mail_cache *cache,
-					const char *function)
-{
-	i_assert(function != NULL);
-
-	if (ENOSPACE(errno)) {
-		cache->index->nodiskspace = TRUE;
-		return FALSE;
-	}
-
-	index_set_error(cache->index, "%s failed with index cache file %s: %m",
-			function, cache->filepath);
-	return FALSE;
-}
-
-static int mail_cache_create_memory(struct mail_cache *cache,
-				    struct mail_cache_header *hdr)
-{
-	cache->mmap_length = MAIL_CACHE_INITIAL_SIZE;
-	cache->mmap_base = mmap_anon(cache->mmap_length);
-	if (cache->mmap_base == MAP_FAILED) {
-		index_set_error(cache->index, "mmap_anon(%"PRIuSIZE_T")",
-				cache->mmap_length);
-		return FALSE;
-	}
-
-	cache->header = cache->mmap_base;
-	*cache->header = *hdr;
-
-	cache->anon_mmap = TRUE;
-	cache->filepath = i_strdup_printf("(in-memory index cache for %s)",
-					  cache->index->mailbox_path);
-	return TRUE;
-}
-
-static void mail_cache_file_close(struct mail_cache *cache)
-{
-	if (cache->anon_mmap) {
-		if (munmap_anon(cache->mmap_base, cache->mmap_length) < 0)
-			mail_cache_set_syscall_error(cache, "munmap_anon()");
-	} else if (cache->mmap_base != NULL) {
-		if (munmap(cache->mmap_base, cache->mmap_length) < 0)
-			mail_cache_set_syscall_error(cache, "munmap()");
-	}
-
-	cache->mmap_base = NULL;
-	cache->header = NULL;
-	cache->mmap_length = 0;
-
-	if (cache->fd != -1) {
-		if (close(cache->fd) < 0)
-			mail_cache_set_syscall_error(cache, "close()");
-		cache->fd = -1;
-	}
-}
-
-static int mail_cache_file_reopen(struct mail_cache *cache)
-{
-	int fd;
-
-	if (cache->anon_mmap) {
-		/* cache was set corrupted, we'll have to quit */
-		return FALSE;
-	}
-
-	fd = open(cache->filepath, O_RDWR);
-	if (fd == -1)
-		return mail_cache_set_syscall_error(cache, "open()");
-
-	mail_cache_file_close(cache);
-
-	cache->fd = fd;
-	return TRUE;
-}
-
-static int mmap_verify_header(struct mail_cache *cache)
-{
-	struct mail_cache_header *hdr;
-
-	/* check that the header is still ok */
-	if (cache->mmap_length < sizeof(struct mail_cache_header))
-		return mail_cache_set_corrupted(cache, "File too small");
-	cache->header = hdr = cache->mmap_base;
-	cache->sync_id = hdr->sync_id;
-
-	if (cache->header->indexid != cache->index->indexid) {
-		/* index id changed */
-		if (cache->header->indexid != 0)
-			mail_cache_set_corrupted(cache, "indexid changed");
-		cache->index->inconsistent = TRUE; /* easiest way to rebuild */
-		return FALSE;
-	}
-
-	if (cache->trans_ctx != NULL) {
-		/* we've updated used_file_size, do nothing */
-		return TRUE;
-	}
-
-	cache->used_file_size = nbo_to_uint32(hdr->used_file_size);
-
-	/* only check the header if we're locked */
-	if (cache->locks == 0)
-		return TRUE;
-
-	if (cache->used_file_size < sizeof(struct mail_cache_header)) {
-		mail_cache_set_corrupted(cache, "used_file_size too small");
-		return FALSE;
-	}
-	if ((cache->used_file_size % sizeof(uint32_t)) != 0) {
-		mail_cache_set_corrupted(cache, "used_file_size not aligned");
-		return FALSE;
-	}
-
-	if (cache->used_file_size > cache->mmap_length) {
-		/* maybe a crash truncated the file - just fix it */
-		hdr->used_file_size = uint32_to_nbo(cache->mmap_length & ~3);
-		if (msync(cache->mmap_base, sizeof(*hdr), MS_SYNC) < 0) 
-			return mail_cache_set_syscall_error(cache, "msync()");
-	}
-	return TRUE;
-}
-
-static int mmap_update_nocheck(struct mail_cache *cache,
-			       size_t offset, size_t size)
-{
-	struct stat st;
-
-	/* if sync id has changed, the file has to be reopened.
-	   note that if main index isn't locked, it may change again */
-	if (cache->sync_id != cache->index->cache_sync_id &&
-	    cache->mmap_base != NULL) {
-		if (!mail_cache_file_reopen(cache))
-			return -1;
-	}
-
-	if (offset < cache->mmap_length &&
-	    size <= cache->mmap_length - offset &&
-	    !cache->mmap_refresh) {
-		/* already mapped */
-		if (size != 0 || cache->anon_mmap)
-			return 1;
-
-		/* requesting the whole file - see if we need to
-		   re-mmap */
-		if (fstat(cache->fd, &st) < 0) {
-			mail_cache_set_syscall_error(cache, "fstat()");
-			return -1;
-		}
-		if ((uoff_t)st.st_size == cache->mmap_length)
-			return 1;
-	}
-	cache->mmap_refresh = FALSE;
-
-	if (cache->anon_mmap)
-		return 1;
-
-	if (cache->mmap_base != NULL) {
-		if (cache->locks != 0) {
-			/* in the middle of transaction - write the changes */
-			if (msync(cache->mmap_base, cache->mmap_length,
-				  MS_SYNC) < 0) {
-				mail_cache_set_syscall_error(cache, "msync()");
-				return -1;
-			}
-		}
-
-		if (munmap(cache->mmap_base, cache->mmap_length) < 0)
-			mail_cache_set_syscall_error(cache, "munmap()");
-	}
-
-	i_assert(cache->fd != -1);
-
-	/* map the whole file */
-	cache->header = NULL;
-	cache->mmap_length = 0;
-
-	cache->mmap_base = mmap_rw_file(cache->fd, &cache->mmap_length);
-	if (cache->mmap_base == MAP_FAILED) {
-		cache->mmap_base = NULL;
-		mail_cache_set_syscall_error(cache, "mmap()");
-		return -1;
-	}
-
-	/* re-mmaped, check header */
-	return 0;
-}
-
-static int mmap_update(struct mail_cache *cache, size_t offset, size_t size)
-{
-	int synced, ret;
-
-	for (synced = FALSE;; synced = TRUE) {
-		ret = mmap_update_nocheck(cache, offset, size);
-		if (ret > 0)
-			return TRUE;
-		if (ret < 0)
-			return FALSE;
-
-		if (!mmap_verify_header(cache))
-			return FALSE;
-
-		/* see if cache file was rebuilt - do it only once to avoid
-		   infinite looping */
-		if (cache->header->sync_id == cache->index->cache_sync_id ||
-		    synced)
-			break;
-
-		if (!mail_cache_file_reopen(cache))
-			return FALSE;
-	}
-	return TRUE;
-}
-
-static int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
-{
-	struct stat st;
-
-	mail_cache_file_close(cache);
-
-	cache->fd = open(cache->filepath, O_RDWR);
-	if (cache->fd == -1) {
-		if (errno == ENOENT)
-			return 0;
-
-		mail_cache_set_syscall_error(cache, "open()");
-		return -1;
-	}
-
-	if (fstat(cache->fd, &st) < 0) {
-		mail_cache_set_syscall_error(cache, "fstat()");
-		return -1;
-	}
-
-	if (st.st_size < sizeof(struct mail_cache_header))
-		return 0;
-
-	cache->mmap_refresh = TRUE;
-	if (mmap_update_nocheck(cache, 0, sizeof(struct mail_cache_header)) < 0)
-		return -1;
-
-	/* verify that this really is the cache for wanted index */
-	cache->silent = silent;
-	if (!mmap_verify_header(cache)) {
-		cache->silent = FALSE;
-		return 0;
-	}
-
-	cache->silent = FALSE;
-	return 1;
-}
-
-static void mail_index_clear_cache_offsets(struct mail_index *index)
-{
-	struct mail_index_record *rec;
-
-	index->sync_stamp = 0;
-
-	rec = index->lookup(index, 1);
-	while (rec != NULL) {
-		rec->cache_offset = 0;
-		rec = index->next(index, rec);
-	}
-}
-
-static int mail_cache_open_or_create_file(struct mail_cache *cache,
-					  struct mail_cache_header *hdr)
-{
-	int ret, fd;
-
-	cache->filepath = i_strconcat(cache->index->filepath,
-				      MAIL_CACHE_FILE_PREFIX, NULL);
-
-	ret = mail_cache_open_and_verify(cache, FALSE);
-	if (ret != 0)
-		return ret > 0;
-
-	/* we'll have to clear cache_offsets which requires exclusive lock */
-	cache->index->inconsistent = FALSE;
-	if (!mail_index_set_lock(cache->index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	/* maybe a rebuild.. */
-	fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
-			       MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-			       MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-	if (fd == -1) {
-		mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-		return FALSE;
-	}
-
-	/* see if someone else just created the cache file */
-	ret = mail_cache_open_and_verify(cache, TRUE);
-	if (ret != 0) {
-		(void)file_dotlock_delete(cache->filepath, fd);
-		return ret > 0;
-	}
-
-	/* rebuild then */
-	if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
-		mail_cache_set_syscall_error(cache, "write_full()");
-		(void)file_dotlock_delete(cache->filepath, fd);
-		return FALSE;
-	}
-	if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
-		mail_cache_set_syscall_error(cache, "file_set_size()");
-		(void)file_dotlock_delete(cache->filepath, fd);
-		return FALSE;
-	}
-
-	mail_index_clear_cache_offsets(cache->index);
-
-	mail_cache_file_close(cache);
-	cache->fd = dup(fd);
-
-	if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
-		mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-		return FALSE;
-	}
-
-	cache->mmap_refresh = TRUE;
-	if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
-		return FALSE;
-
-	return TRUE;
-}
-
-int mail_cache_open_or_create(struct mail_index *index)
-{
-        struct mail_cache_header hdr;
-	struct mail_cache *cache;
-
-	memset(&hdr, 0, sizeof(hdr));
-	hdr.indexid = index->indexid;
-	hdr.sync_id = index->cache_sync_id;
-	hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
-
-	cache = i_new(struct mail_cache, 1);
-	cache->index = index;
-	cache->fd = -1;
-        cache->split_header_pool = pool_alloconly_create("Headers", 512);
-
-	index->cache = cache;
-
-	/* we'll do anon-mmaping only if initially requested. if we fail
-	   because of out of disk space, we'll just let the main index code
-	   know it and fail. */
-	if (INDEX_IS_IN_MEMORY(index)) {
-		if (!mail_cache_create_memory(cache, &hdr)) {
-			mail_cache_free(cache);
-			return FALSE;
-		}
-	} else {
-		if (!mail_cache_open_or_create_file(cache, &hdr)) {
-			mail_cache_free(cache);
-			return FALSE;
-		}
-	}
-
-	/* unset inconsistency - we already rebuilt the cache file */
-	index->inconsistent = FALSE;
-
-	return TRUE;
-}
-
-void mail_cache_free(struct mail_cache *cache)
-{
-	i_assert(cache->trans_ctx == NULL);
-
-	cache->index->cache = NULL;
-
-	mail_cache_file_close(cache);
-
-	pool_unref(cache->split_header_pool);
-	i_free(cache->filepath);
-	i_free(cache);
-}
-
-void mail_cache_set_defaults(struct mail_cache *cache,
-			     enum mail_cache_field default_cache_fields,
-			     enum mail_cache_field never_cache_fields)
-{
-	cache->default_cache_fields = default_cache_fields;
-	cache->never_cache_fields = never_cache_fields;
-}
-
-static const struct mail_cache_record *
-mail_cache_compress_record(struct mail_cache *cache,
-			   struct mail_index_record *rec, int header_idx,
-			   uint32_t *size_r)
-{
-	enum mail_cache_field orig_cached_fields, cached_fields, field;
-	struct mail_cache_record cache_rec;
-	buffer_t *buffer;
-	const void *data;
-	size_t size, pos;
-	uint32_t nb_size;
-	int i;
-
-	memset(&cache_rec, 0, sizeof(cache_rec));
-	buffer = buffer_create_dynamic(pool_datastack_create(),
-				       4096, (size_t)-1);
-
-        orig_cached_fields = mail_cache_get_fields(cache, rec);
-	cached_fields = orig_cached_fields & ~MAIL_CACHE_HEADERS_MASK;
-	buffer_append(buffer, &cache_rec, sizeof(cache_rec));
-	for (i = 0, field = 1; i < 31; i++, field <<= 1) {
-		if ((cached_fields & field) == 0)
-			continue;
-
-		if (!mail_cache_lookup_field(cache, rec, field, &data, &size)) {
-			cached_fields &= ~field;
-			continue;
-		}
-
-		nb_size = uint32_to_nbo((uint32_t)size);
-
-		if ((field & MAIL_CACHE_FIXED_MASK) == 0)
-			buffer_append(buffer, &nb_size, sizeof(nb_size));
-		buffer_append(buffer, data, size);
-		if ((size & 3) != 0)
-			buffer_append(buffer, null4, 4 - (size & 3));
-	}
-
-	/* now merge all the headers if we have them all */
-	if ((orig_cached_fields & mail_cache_header_fields[header_idx]) != 0) {
-		nb_size = 0;
-		pos = buffer_get_used_size(buffer);
-		buffer_append(buffer, &nb_size, sizeof(nb_size));
-
-		for (i = 0; i <= header_idx; i++) {
-			field = mail_cache_header_fields[i];
-			if (mail_cache_lookup_field(cache, rec, field,
-						    &data, &size) && size > 1) {
-				size--; /* terminating \0 */
-				buffer_append(buffer, data, size);
-				nb_size += size;
-			}
-		}
-		buffer_append(buffer, "", 1);
-		nb_size++;
-		if ((nb_size & 3) != 0)
-			buffer_append(buffer, null4, 4 - (nb_size & 3));
-
-		nb_size = uint32_to_nbo(nb_size);
-		buffer_write(buffer, pos, &nb_size, sizeof(nb_size));
-
-		cached_fields |= MAIL_CACHE_HEADERS1;
-	}
-
-	cache_rec.fields = cached_fields;
-	cache_rec.size = uint32_to_nbo(buffer_get_used_size(buffer));
-	buffer_write(buffer, 0, &cache_rec, sizeof(cache_rec));
-
-	data = buffer_get_data(buffer, &size);
-	*size_r = size;
-	return data;
-}
-
-static int mail_cache_copy(struct mail_cache *cache, int fd)
-{
-	struct mail_cache_header *hdr;
-	const struct mail_cache_record *cache_rec;
-	struct mail_index_record *rec;
-        enum mail_cache_field used_fields;
-	unsigned char *mmap_base;
-	const char *str;
-	uint32_t new_file_size, offset, size, nb_size;
-	int i, header_idx;
-
-	/* pick some reasonably good file size */
-	new_file_size = cache->used_file_size -
-		nbo_to_uint32(cache->header->deleted_space);
-	new_file_size = (new_file_size + 1023) & ~1023;
-	if (new_file_size < MAIL_CACHE_INITIAL_SIZE)
-		new_file_size = MAIL_CACHE_INITIAL_SIZE;
-
-	if (file_set_size(fd, new_file_size) < 0)
-		return mail_cache_set_syscall_error(cache, "file_set_size()");
-
-	mmap_base = mmap(NULL, new_file_size, PROT_READ | PROT_WRITE,
-			 MAP_SHARED, fd, 0);
-	if (mmap_base == MAP_FAILED)
-		return mail_cache_set_syscall_error(cache, "mmap()");
-
-	/* skip file's header */
-	hdr = (struct mail_cache_header *) mmap_base;
-	offset = sizeof(*hdr);
-
-	/* merge all the header pieces into one. if some message doesn't have
-	   all the required pieces, we'll just have to drop them all. */
-	for (i = MAIL_CACHE_HEADERS_COUNT-1; i >= 0; i--) {
-		str = mail_cache_get_header_fields_str(cache, i);
-		if (str != NULL)
-			break;
-	}
-
-	if (str == NULL)
-		header_idx = -1;
-	else {
-		hdr->header_offsets[0] = uint32_to_offset(offset);
-		header_idx = i;
-
-		size = strlen(str) + 1;
-		nb_size = uint32_to_nbo(size);
-
-		memcpy(mmap_base + offset, &nb_size, sizeof(nb_size));
-		offset += sizeof(nb_size);
-		memcpy(mmap_base + offset, str, size);
-		offset += (size + 3) & ~3;
-	}
-
-	used_fields = 0;
-	rec = cache->index->lookup(cache->index, 1);
-	while (rec != NULL) {
-		cache_rec = mail_cache_lookup(cache, rec, 0);
-		if (cache_rec == NULL)
-			rec->cache_offset = 0;
-		else if (offset_to_uint32(cache_rec->next_offset) == 0) {
-			/* just one unmodified block, copy it */
-			size = nbo_to_uint32(cache_rec->size);
-			i_assert(offset + size <= new_file_size);
-
-			memcpy(mmap_base + offset, cache_rec, size);
-			rec->cache_offset = uint32_to_offset(offset);
-
-			size = (size + 3) & ~3;
-			offset += size;
-		} else {
-			/* multiple blocks, sort them into buffer */
-			t_push();
-			cache_rec = mail_cache_compress_record(cache, rec,
-							       header_idx,
-							       &size);
-			i_assert(offset + size <= new_file_size);
-			memcpy(mmap_base + offset, cache_rec, size);
-			used_fields |= cache_rec->fields;
-			t_pop();
-
-			rec->cache_offset = uint32_to_offset(offset);
-			offset += size;
-		}
-
-		rec = cache->index->next(cache->index, rec);
-	}
-
-	/* update header */
-	hdr->indexid = cache->index->indexid;
-	hdr->sync_id = cache->sync_id = cache->index->cache_sync_id =
-		++cache->index->header->cache_sync_id;
-	hdr->used_file_size = uint32_to_nbo(offset);
-	hdr->used_fields = used_fields;
-	hdr->field_usage_start = uint32_to_nbo(ioloop_time);
-
-	/* write everything to disk */
-	if (msync(mmap_base, offset, MS_SYNC) < 0)
-		return mail_cache_set_syscall_error(cache, "msync()");
-
-	if (munmap(mmap_base, new_file_size) < 0)
-		return mail_cache_set_syscall_error(cache, "munmap()");
-
-	if (fdatasync(fd) < 0)
-		return mail_cache_set_syscall_error(cache, "fdatasync()");
-	return TRUE;
-}
-
-int mail_cache_compress(struct mail_cache *cache)
-{
-	int fd, ret = TRUE;
-
-	i_assert(cache->trans_ctx == NULL);
-
-	if (cache->anon_mmap)
-		return TRUE;
-
-	if (!cache->index->set_lock(cache->index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	if (mail_cache_lock(cache, TRUE) <= 0)
-		return FALSE;
-
-#ifdef DEBUG
-	i_warning("Compressing cache file %s", cache->filepath);
-#endif
-
-	fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
-			       MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-			       MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-	if (fd == -1) {
-		mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-		return FALSE;
-	}
-
-	/* now we'll begin the actual moving. keep rebuild-flag on
-	   while doing it. */
-	cache->index->header->flags |= MAIL_INDEX_HDR_FLAG_REBUILD;
-	if (!mail_index_fmdatasync(cache->index, cache->index->header_size))
-		return FALSE;
-
-	if (!mail_cache_copy(cache, fd)) {
-		(void)file_dotlock_delete(cache->filepath, fd);
-		ret = FALSE;
-	} else {
-		mail_cache_file_close(cache);
-		cache->fd = dup(fd);
-
-		if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
-			mail_cache_set_syscall_error(cache,
-						     "file_dotlock_replace()");
-			ret = FALSE;
-		}
-
-		if (!mmap_update(cache, 0, 0))
-			ret = FALSE;
-	}
-
-	/* headers could have changed, reread them */
-	memset(cache->split_offsets, 0, sizeof(cache->split_offsets));
-	memset(cache->split_headers, 0, sizeof(cache->split_headers));
-
-	if (ret) {
-		cache->index->header->flags &=
-			~(MAIL_INDEX_HDR_FLAG_REBUILD |
-			  MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE);
-	}
-
-	if (!mail_cache_unlock(cache))
-		ret = FALSE;
-
-	return ret;
-}
-
-int mail_cache_truncate(struct mail_cache *cache)
-{
-	struct mail_cache_header hdr;
-	int ret, fd;
-
-	i_assert(cache->index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	memset(&hdr, 0, sizeof(hdr));
-	hdr.indexid = cache->index->indexid;
-	hdr.sync_id = cache->sync_id = cache->index->cache_sync_id =
-		++cache->index->header->cache_sync_id;
-	hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
-	cache->used_file_size = sizeof(hdr);
-
-	if (cache->anon_mmap) {
-		*cache->header = hdr;
-		return TRUE;
-	}
-
-	ret = mail_cache_open_and_verify(cache, TRUE);
-	if (ret != 0)
-		return ret > 0;
-
-	fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
-			       MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-			       MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-	if (fd == -1) {
-		mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-		return FALSE;
-	}
-
-	if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
-		mail_cache_set_syscall_error(cache, "write_full()");
-		(void)file_dotlock_delete(cache->filepath, fd);
-		return FALSE;
-	}
-	if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
-		mail_cache_set_syscall_error(cache, "file_set_size()");
-		(void)file_dotlock_delete(cache->filepath, fd);
-		return FALSE;
-	}
-
-	mail_cache_file_close(cache);
-	cache->fd = dup(fd);
-
-	if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
-		mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-		return FALSE;
-	}
-
-	cache->mmap_refresh = TRUE;
-	if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
-		return FALSE;
-
-	return TRUE;
-}
-
-int mail_cache_mark_file_deleted(struct mail_cache *cache)
-{
-	uint32_t indexid = 0;
-
-	if (cache->anon_mmap)
-		cache->header->indexid = 0;
-	else {
-		if (pwrite(cache->fd, &indexid, sizeof(indexid), 0) < 0)
-			return mail_cache_set_syscall_error(cache, "pwrite()");
-	}
-	return TRUE;
-}
-
-int mail_cache_lock(struct mail_cache *cache, int nonblock)
-{
-	int ret;
-
-	if (cache->locks++ != 0)
-		return TRUE;
-
-	if (cache->anon_mmap)
-		return TRUE;
-
-	if (nonblock) {
-		ret = file_try_lock(cache->fd, F_WRLCK);
-		if (ret < 0)
-			mail_cache_set_syscall_error(cache, "file_try_lock()");
-	} else {
-		ret = file_wait_lock(cache->fd, F_WRLCK);
-		if (ret <= 0)
-			mail_cache_set_syscall_error(cache, "file_wait_lock()");
-	}
-
-	if (ret > 0) {
-		if (!mmap_update(cache, 0, 0)) {
-			(void)mail_cache_unlock(cache);
-			return -1;
-		}
-		if (cache->sync_id != cache->index->cache_sync_id) {
-			/* we have the cache file locked and sync_id still
-			   doesn't match. it means we crashed between updating
-			   cache file and updating sync_id in index header.
-			   just update the sync_ids so they match. */
-			i_warning("Updating broken sync_id in cache file %s",
-				  cache->filepath);
-			cache->sync_id = cache->header->sync_id =
-				cache->index->cache_sync_id;
-		}
-	}
-	return ret;
-}
-
-int mail_cache_unlock(struct mail_cache *cache)
-{
-	if (--cache->locks > 0)
-		return TRUE;
-
-	if (cache->anon_mmap)
-		return TRUE;
-
-	if (file_wait_lock(cache->fd, F_UNLCK) <= 0) {
-		mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-void mail_cache_unlock_later(struct mail_cache *cache)
-{
-	cache->index->cache_later_locks++;
-}
-
-int mail_cache_is_locked(struct mail_cache *cache)
-{
-	return cache->locks > 0;
-}
-
-int mail_cache_transaction_begin(struct mail_cache *cache, int nonblock,
-				 struct mail_cache_transaction_ctx **ctx_r)
-{
-	int ret;
-
-	i_assert(cache->trans_ctx == NULL);
-
-	ret = mail_cache_lock(cache, nonblock);
-	if (ret <= 0)
-		return ret;
-
-	*ctx_r = i_new(struct mail_cache_transaction_ctx, 1);
-	(*ctx_r)->cache = cache;
-	(*ctx_r)->cache_data =
-		buffer_create_dynamic(system_pool, 8192, (size_t)-1);
-	(*ctx_r)->last_idx = (unsigned int)-1;
-
-	cache->trans_ctx = *ctx_r;
-	return 1;
-}
-
-int mail_cache_transaction_end(struct mail_cache_transaction_ctx *ctx)
-{
-	int ret = TRUE;
-
-	i_assert(ctx->cache->trans_ctx != NULL);
-
-	(void)mail_cache_transaction_rollback(ctx);
-
-	if (!mail_cache_unlock(ctx->cache))
-		ret = FALSE;
-
-	ctx->cache->trans_ctx = NULL;
-
-	if (ctx->cache_marks != NULL)
-		buffer_free(ctx->cache_marks);
-	if (ctx->index_marks != NULL)
-		buffer_free(ctx->index_marks);
-	buffer_free(ctx->cache_data);
-	i_free(ctx);
-	return ret;
-}
-
-static void mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
-{
-	memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
-	ctx->last_idx = (unsigned int)-1;
-
-	ctx->next_unused_header_lowwater = 0;
-	ctx->first_uid = ctx->last_uid = ctx->prev_uid = 0;
-	ctx->prev_fields = 0;
-
-	if (ctx->cache_marks != NULL)
-		buffer_set_used_size(ctx->cache_marks, 0);
-	if (ctx->index_marks != NULL)
-		buffer_set_used_size(ctx->index_marks, 0);
-	buffer_set_used_size(ctx->cache_data, 0);
-}
-
-static void mark_update(buffer_t **buf, uint32_t offset, uint32_t data)
-{
-	if (*buf == NULL)
-		*buf = buffer_create_dynamic(system_pool, 1024, (size_t)-1);
-
-	/* data is in big endian, we want to update only the lowest byte */
-	buffer_append(*buf, &offset, sizeof(offset));
-	buffer_append(*buf, &data, sizeof(data));
-}
-
-static int write_mark_updates(struct mail_index *index, buffer_t *marks,
-			      const char *path, int fd)
-{
-	const uint32_t *data, *end;
-	size_t size;
-
-	data = buffer_get_data(marks, &size);
-	end = data + size/sizeof(uint32_t);
-
-	while (data < end) {
-		if (pwrite(fd, data+1, sizeof(*data), data[0]) < 0) {
-			index_file_set_syscall_error(index, path, "pwrite()");
-			return FALSE;
-		}
-		data += 2;
-	}
-	return TRUE;
-}
-
-static void write_mark_updates_in_memory(buffer_t *marks, void *mmap_base,
-					 size_t mmap_length)
-{
-	const unsigned char *data, *end;
-	uint32_t offset;
-	size_t size;
-
-	data = buffer_get_data(marks, &size);
-	end = data + size;
-
-	while (data < end) {
-		memcpy(&offset, data, sizeof(offset));
-		data += sizeof(offset);
-
-		i_assert(offset <= mmap_length - sizeof(uint32_t));
-		memcpy((char *) mmap_base + offset, data, sizeof(uint32_t));
-		data += sizeof(uint32_t);
-	}
-}
-
-static void commit_all_changes_in_memory(struct mail_cache_transaction_ctx *ctx)
-{
-	struct mail_cache *cache = ctx->cache;
-
-	if (ctx->cache_marks != NULL) {
-		write_mark_updates_in_memory(ctx->cache_marks,
-					     cache->mmap_base,
-					     cache->mmap_length);
-	}
-	if (ctx->index_marks != NULL) {
-		write_mark_updates_in_memory(ctx->index_marks,
-					     cache->index->mmap_base,
-					     cache->index->mmap_used_length);
-	}
-}
-
-static int commit_all_changes(struct mail_cache_transaction_ctx *ctx)
-{
-	struct mail_cache *cache = ctx->cache;
-	uint32_t cont;
-
-	if (ctx->cache->anon_mmap) {
-		commit_all_changes_in_memory(ctx);
-		return TRUE;
-	}
-
-	/* write everything to disk */
-	if (msync(cache->mmap_base, cache->mmap_length, MS_SYNC) < 0)
-		return mail_cache_set_syscall_error(cache, "msync()");
-
-	if (fdatasync(cache->fd) < 0)
-		return mail_cache_set_syscall_error(cache, "fdatasync()");
-
-	if (ctx->cache_marks != NULL &&
-	    buffer_get_used_size(ctx->cache_marks) != 0) {
-		/* now that we're sure it's there, set on all the used-bits */
-		if (!write_mark_updates(cache->index, ctx->cache_marks,
-					cache->filepath, cache->fd))
-			return FALSE;
-
-		/* update continued records count */
-		cont = nbo_to_uint32(cache->header->continued_record_count);
-
-		cont += buffer_get_used_size(ctx->cache_marks) /
-			(sizeof(uint32_t) * 2);
-
-		if (cont * 100 / cache->index->header->messages_count >=
-		    COMPRESS_CONTINUED_PERCENTAGE &&
-		    cache->used_file_size >= COMPRESS_MIN_SIZE) {
-			/* too many continued rows, compress */
-			cache->index->set_flags |=
-				MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
-		}
-
-		cache->header->continued_record_count = uint32_to_nbo(cont);
-	}
-
-	/* write index last */
-	if (ctx->index_marks != NULL &&
-	    buffer_get_used_size(ctx->index_marks) != 0) {
-		if (!mail_index_fmdatasync(cache->index,
-					   cache->index->mmap_used_length))
-			return FALSE;
-
-		if (!write_mark_updates(cache->index, ctx->index_marks,
-					cache->index->filepath,
-					cache->index->fd))
-			return FALSE;
-	}
-	return TRUE;
-}
-
-int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
-{
-	int ret = TRUE;
-
-	if (ctx->last_idx != (unsigned int)-1) {
-		if (!mail_cache_write(ctx))
-			return FALSE;
-	}
-
-	ctx->cache->header->used_file_size =
-		uint32_to_nbo(ctx->cache->used_file_size);
-
-	if (!commit_all_changes(ctx))
-		ret = FALSE;
-
-	if (ctx->next_unused_header_lowwater == MAIL_CACHE_HEADERS_COUNT) {
-		/* they're all used - compress the cache to get more */
-		ctx->cache->index->set_flags |=
-			MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
-	}
-
-	mail_cache_transaction_flush(ctx);
-	return ret;
-}
-
-int mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
-{
-	struct mail_cache *cache = ctx->cache;
-	unsigned int i;
-
-	/* no need to actually modify the file - we just didn't update
-	   used_file_size */
-	cache->used_file_size = nbo_to_uint32(cache->header->used_file_size);
-
-	/* make sure we don't cache the headers */
-	for (i = 0; i < ctx->next_unused_header_lowwater; i++) {
-		if (offset_to_uint32(cache->header->header_offsets[i]) == 0)
-			cache->split_offsets[i] = 1;
-	}
-
-	mail_cache_transaction_flush(ctx);
-	return TRUE;
-}
-
-static int mail_cache_grow(struct mail_cache *cache, uint32_t size)
-{
-	struct stat st;
-	void *base;
-	uoff_t grow_size, new_fsize;
-
-	new_fsize = cache->used_file_size + size;
-	grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
-	if (grow_size < 16384)
-		grow_size = 16384;
-
-	new_fsize += grow_size;
-	new_fsize &= ~1023;
-
-	if (cache->anon_mmap) {
-		i_assert(new_fsize < SSIZE_T_MAX);
-
-		base = mremap_anon(cache->mmap_base, cache->mmap_length,
-				   (size_t)new_fsize, MREMAP_MAYMOVE);
-		if (base == MAP_FAILED) {
-			mail_cache_set_syscall_error(cache, "mremap_anon()");
-			return FALSE;
-		}
-
-		cache->mmap_base = base;
-		cache->mmap_length = (size_t)new_fsize;
-		cache->header = cache->mmap_base;
-		return TRUE;
-	}
-
-	if (fstat(cache->fd, &st) < 0)
-		return mail_cache_set_syscall_error(cache, "fstat()");
-
-	if (cache->used_file_size + size <= (uoff_t)st.st_size) {
-		/* no need to grow, just update mmap */
-		if (!mmap_update(cache, 0, 0))
-			return FALSE;
-
-		i_assert(cache->mmap_length >= (uoff_t)st.st_size);
-		return TRUE;
-	}
-
-	if (st.st_size < (off_t)sizeof(struct mail_cache_header))
-		return mail_cache_set_corrupted(cache, "Header is missing");
-
-	if (file_set_size(cache->fd, (off_t)new_fsize) < 0)
-		return mail_cache_set_syscall_error(cache, "file_set_size()");
-
-	return mmap_update(cache, 0, 0);
-}
-
-static uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
-					uint32_t size)
-{
-	/* NOTE: must be done within transaction or rollback would break it */
-	uint32_t offset;
-
-	i_assert((size & 3) == 0);
-
-	offset = ctx->cache->used_file_size;
-	if (offset >= 0x40000000) {
-		index_set_error(ctx->cache->index, "Cache file too large: %s",
-				ctx->cache->filepath);
-		return 0;
-	}
-
-	if (offset + size > ctx->cache->mmap_length) {
-		if (!mail_cache_grow(ctx->cache, size))
-			return 0;
-	}
-
-	ctx->cache->used_file_size += size;
-	return offset;
-}
-
-static const char *
-mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
-{
-	uint32_t offset, data_size;
-	unsigned char *buf;
-
-	offset = offset_to_uint32(cache->header->header_offsets[idx]);
-
-	if (offset == 0)
-		return NULL;
-
-	if (!mmap_update(cache, offset, 1024))
-		return NULL;
-
-	if (offset + sizeof(data_size) > cache->mmap_length) {
-		mail_cache_set_corrupted(cache, "Header %u points outside file",
-					 idx);
-		return NULL;
-	}
-
-	buf = cache->mmap_base;
-	memcpy(&data_size, buf + offset, sizeof(data_size));
-	data_size = nbo_to_uint32(data_size);
-	offset += sizeof(data_size);
-
-	if (data_size == 0) {
-		mail_cache_set_corrupted(cache,
-			"Header %u points to empty string", idx);
-		return NULL;
-	}
-
-	if (!mmap_update(cache, offset, data_size))
-		return NULL;
-
-	if (offset + data_size > cache->mmap_length) {
-		mail_cache_set_corrupted(cache, "Header %u points outside file",
-					 idx);
-		return NULL;
-	}
-
-	buf = cache->mmap_base;
-	if (buf[offset + data_size - 1] != '\0') {
-		mail_cache_set_corrupted(cache,
-			"Header %u points to invalid string", idx);
-		return NULL;
-	}
-
-	return buf + offset;
-}
-
-static const char *const *
-split_header(struct mail_cache *cache, const char *header)
-{
-	const char *const *arr, *const *tmp;
-	const char *null = NULL;
-	char *str;
-	buffer_t *buf;
-
-	if (header == NULL)
-		return NULL;
-
-	arr = t_strsplit(header, "\n");
-	buf = buffer_create_dynamic(cache->split_header_pool, 32, (size_t)-1);
-	for (tmp = arr; *tmp != NULL; tmp++) {
-		str = p_strdup(cache->split_header_pool, *tmp);
-		buffer_append(buf, &str, sizeof(str));
-	}
-	buffer_append(buf, &null, sizeof(null));
-
-	return buffer_get_data(buf, NULL);
-}
-
-const char *const *mail_cache_get_header_fields(struct mail_cache *cache,
-						unsigned int idx)
-{
-	const char *str;
-	int i;
-
-	i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
-
-	/* t_strsplit() is a bit slow, so we cache it */
-	if (cache->header->header_offsets[idx] != cache->split_offsets[idx]) {
-		p_clear(cache->split_header_pool);
-
-		t_push();
-		for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
-			cache->split_offsets[i] =
-				cache->header->header_offsets[i];
-
-			str = mail_cache_get_header_fields_str(cache, i);
-			cache->split_headers[i] = split_header(cache, str);
-		}
-		t_pop();
-	}
-
-	return cache->split_headers[idx];
-}
-
-static const char *write_header_string(const char *const headers[],
-				       uint32_t *size_r)
-{
-	buffer_t *buffer;
-	size_t size;
-
-	buffer = buffer_create_dynamic(pool_datastack_create(),
-				       512, (size_t)-1);
-
-	while (*headers != NULL) {
-		if (buffer_get_used_size(buffer) != 0)
-			buffer_append(buffer, "\n", 1);
-		buffer_append(buffer, *headers, strlen(*headers));
-		headers++;
-	}
-	buffer_append(buffer, null4, 1);
-
-	size = buffer_get_used_size(buffer);
-	if ((size & 3) != 0) {
-		buffer_append(buffer, null4, 4 - (size & 3));
-		size += 4 - (size & 3);
-	}
-	*size_r = size;
-	return buffer_get_data(buffer, NULL);
-}
-
-int mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
-				 unsigned int idx, const char *const headers[])
-{
-	struct mail_cache *cache = ctx->cache;
-	uint32_t offset, update_offset, size;
-	const char *header_str, *prev_str;
-
-	i_assert(*headers != NULL);
-	i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
-	i_assert(idx >= ctx->next_unused_header_lowwater);
-	i_assert(offset_to_uint32(cache->header->header_offsets[idx]) == 0);
-
-	t_push();
-
-	header_str = write_header_string(headers, &size);
-	if (idx != 0) {
-		prev_str = mail_cache_get_header_fields_str(cache, idx-1);
-		if (prev_str == NULL) {
-			t_pop();
-			return FALSE;
-		}
-
-		i_assert(strcmp(header_str, prev_str) != 0);
-	}
-
-	offset = mail_cache_append_space(ctx, size + sizeof(uint32_t));
-	if (offset != 0) {
-		memcpy((char *) cache->mmap_base + offset + sizeof(uint32_t),
-		       header_str, size);
-
-		size = uint32_to_nbo(size);
-		memcpy((char *) cache->mmap_base + offset,
-		       &size, sizeof(uint32_t));
-
-		/* update cached headers */
-		cache->split_offsets[idx] = cache->header->header_offsets[idx];
-		cache->split_headers[idx] = split_header(cache, header_str);
-
-		/* mark used-bit to be updated later. not really needed for
-		   read-safety, but if transaction get rolled back we can't let
-		   this point to invalid location. */
-		update_offset = (char *) &cache->header->header_offsets[idx] -
-			(char *) cache->mmap_base;
-		mark_update(&ctx->cache_marks, update_offset,
-			    uint32_to_offset(offset));
-
-		/* make sure get_header_fields() still works for this header
-		   while the transaction isn't yet committed. */
-		ctx->next_unused_header_lowwater = idx + 1;
-	}
-
-	t_pop();
-	return offset > 0;
-}
-
-static struct mail_cache_record *
-cache_get_record(struct mail_cache *cache, uint32_t offset)
-{
-#define CACHE_PREFETCH 1024
-	struct mail_cache_record *cache_rec;
-	size_t size;
-
-	offset = offset_to_uint32(offset);
-	if (offset == 0)
-		return NULL;
-
-	if (!mmap_update(cache, offset, sizeof(*cache_rec) + CACHE_PREFETCH))
-		return NULL;
-
-	if (offset + sizeof(*cache_rec) > cache->mmap_length) {
-		mail_cache_set_corrupted(cache, "record points outside file");
-		return NULL;
-	}
-	cache_rec = CACHE_RECORD(cache, offset);
-
-	size = nbo_to_uint32(cache_rec->size);
-	if (size < sizeof(*cache_rec)) {
-		mail_cache_set_corrupted(cache, "invalid record size");
-		return NULL;
-	}
-	if (size > CACHE_PREFETCH) {
-		if (!mmap_update(cache, offset, size))
-			return NULL;
-	}
-
-	if (offset + size > cache->mmap_length) {
-		mail_cache_set_corrupted(cache, "record points outside file");
-		return NULL;
-	}
-	return cache_rec;
-}
-
-static struct mail_cache_record *
-cache_get_next_record(struct mail_cache *cache, struct mail_cache_record *rec)
-{
-	struct mail_cache_record *next;
-
-	next = cache_get_record(cache, rec->next_offset);
-	if (next != NULL && next <= rec) {
-		mail_cache_set_corrupted(cache, "next_offset points backwards");
-		return NULL;
-	}
-	return next;
-}
-
-static int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
-{
-	struct mail_cache *cache = ctx->cache;
-	struct mail_cache_record *cache_rec, *next;
-	struct mail_index_record *rec;
-	uint32_t write_offset, update_offset;
-	const void *buf;
-	size_t size, buf_size;
-
-	buf = buffer_get_data(ctx->cache_data, &buf_size);
-
-	size = sizeof(*cache_rec) + buf_size;
-	ctx->cache_rec.size = uint32_to_nbo(size);
-
-	write_offset = mail_cache_append_space(ctx, size);
-	if (write_offset == 0)
-		return FALSE;
-
-	rec = INDEX_RECORD_AT(ctx->cache->index, ctx->last_idx);
-	ctx->last_idx = (unsigned int)-1;
-
-	cache_rec = cache_get_record(cache, rec->cache_offset);
-	if (cache_rec == NULL) {
-		/* first cache record - update offset in index file */
-		i_assert(cache->index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-		/* mark cache_offset to be updated later */
-		update_offset = (char *) &rec->cache_offset -
-			(char *) cache->index->mmap_base;
-		mark_update(&ctx->index_marks, update_offset,
-			    uint32_to_offset(write_offset));
-	} else {
-		/* find the last cache record */
-		while ((next = cache_get_next_record(cache, cache_rec)) != NULL)
-			cache_rec = next;
-
-		/* mark next_offset to be updated later */
-		update_offset = (char *) &cache_rec->next_offset -
-			(char *) cache->mmap_base;
-		mark_update(&ctx->cache_marks, update_offset,
-			    uint32_to_offset(write_offset));
-	}
-
-	memcpy((char *) cache->mmap_base + write_offset,
-	       &ctx->cache_rec, sizeof(ctx->cache_rec));
-	memcpy((char *) cache->mmap_base + write_offset +
-	       sizeof(ctx->cache_rec), buf, buf_size);
-
-	/* reset the write context */
-	memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
-	buffer_set_used_size(ctx->cache_data, 0);
-	return TRUE;
-}
-
-static struct mail_cache_record *
-mail_cache_lookup(struct mail_cache *cache, const struct mail_index_record *rec,
-		  enum mail_cache_field fields)
-{
-	struct mail_cache_record *cache_rec;
-	unsigned int idx;
-
-	if (cache->trans_ctx != NULL &&
-	    cache->trans_ctx->first_uid <= rec->uid &&
-	    cache->trans_ctx->last_uid >= rec->uid &&
-	    (cache->trans_ctx->prev_uid != rec->uid || fields == 0 ||
-	     (cache->trans_ctx->prev_fields & fields) != 0)) {
-		/* we have to auto-commit since we're not capable of looking
-		   into uncommitted records. it would be possible by checking
-		   index_marks and cache_marks, but it's just more trouble
-		   than worth. */
-		idx = INDEX_RECORD_INDEX(cache->index, rec);
-		if (cache->trans_ctx->last_idx == idx) {
-			if (!mail_cache_write(cache->trans_ctx))
-				return NULL;
-		}
-
-		if (!mail_cache_transaction_commit(cache->trans_ctx))
-			return NULL;
-	}
-
-	cache_rec = cache_get_record(cache, rec->cache_offset);
-	if (cache_rec == NULL)
-		return NULL;
-
-	return cache_rec;
-}
-
-static int get_field_num(enum mail_cache_field field)
-{
-	unsigned int mask;
-	int i;
-
-	for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
-		if ((field & mask) != 0)
-			return i;
-	}
-
-	return -1;
-}
-
-static size_t get_insert_offset(struct mail_cache_transaction_ctx *ctx,
-				enum mail_cache_field field)
-{
-	const unsigned char *buf;
-	unsigned int mask;
-	uint32_t data_size;
-	size_t offset = 0;
-	int i;
-
-	buf = buffer_get_data(ctx->cache_data, NULL);
-
-	for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
-		if ((field & mask) != 0)
-			return offset;
-
-		if ((ctx->cache_rec.fields & mask) != 0) {
-			if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
-				data_size = mail_cache_field_sizes[i];
-			else {
-				memcpy(&data_size, buf + offset,
-				       sizeof(data_size));
-				data_size = nbo_to_uint32(data_size);
-				offset += sizeof(data_size);
-			}
-			offset += (data_size + 3) & ~3;
-		}
-	}
-
-	i_unreached();
-	return offset;
-}
-
-int mail_cache_add(struct mail_cache_transaction_ctx *ctx,
-		   struct mail_index_record *rec, enum mail_cache_field field,
-		   const void *data, size_t data_size)
-{
-	uint32_t nb_data_size;
-	size_t full_size, offset;
-	unsigned char *buf;
-	unsigned int idx;
-	int field_num;
-
-	i_assert(data_size > 0);
-	i_assert(data_size < (uint32_t)-1);
-
-	nb_data_size = uint32_to_nbo((uint32_t)data_size);
-
-	if ((field & MAIL_CACHE_FIXED_MASK) != 0) {
-		field_num = get_field_num(field);
-		i_assert(field_num != -1);
-		i_assert(mail_cache_field_sizes[field_num] == data_size);
-	} else if ((field & MAIL_CACHE_STRING_MASK) != 0) {
-		i_assert(((char *) data)[data_size-1] == '\0');
-	}
-
-	/* NOTE: we use index because the record pointer might not last. */
-        idx = INDEX_RECORD_INDEX(ctx->cache->index, rec);
-	if (ctx->last_idx != idx && ctx->last_idx != (unsigned int)-1) {
-		if (!mail_cache_write(ctx))
-			return FALSE;
-	}
-	ctx->last_idx = idx;
-
-	i_assert((ctx->cache_rec.fields & field) == 0);
-
-	full_size = (data_size + 3) & ~3;
-	if ((field & MAIL_CACHE_FIXED_MASK) == 0)
-		full_size += sizeof(nb_data_size);
-
-	/* fields must be ordered. find where to insert it. */
-	if (field > ctx->cache_rec.fields)
-                buf = buffer_append_space_unsafe(ctx->cache_data, full_size);
-	else {
-		offset = get_insert_offset(ctx, field);
-		buffer_copy(ctx->cache_data, offset + full_size,
-			    ctx->cache_data, offset, (size_t)-1);
-		buf = buffer_get_space_unsafe(ctx->cache_data,
-					      offset, full_size);
-	}
-	ctx->cache_rec.fields |= field;
-
-	/* @UNSAFE */
-	if ((field & MAIL_CACHE_FIXED_MASK) == 0) {
-		memcpy(buf, &nb_data_size, sizeof(nb_data_size));
-		buf += sizeof(nb_data_size);
-	}
-	memcpy(buf, data, data_size); buf += data_size;
-	if ((data_size & 3) != 0)
-		memset(buf, 0, 4 - (data_size & 3));
-
-	/* remember the transaction uid range */
-	if (rec->uid < ctx->first_uid || ctx->first_uid == 0)
-		ctx->first_uid = rec->uid;
-	if (rec->uid > ctx->last_uid)
-		ctx->last_uid = rec->uid;
-
-	if (ctx->prev_uid != rec->uid) {
-		ctx->prev_uid = rec->uid;
-		ctx->prev_fields = 0;
-	}
-	ctx->prev_fields |= field;
-
-	return TRUE;
-}
-
-int mail_cache_delete(struct mail_cache_transaction_ctx *ctx,
-		      struct mail_index_record *rec)
-{
-	struct mail_cache *cache = ctx->cache;
-	struct mail_cache_record *cache_rec;
-	uint32_t deleted_space;
-	uoff_t max_del_space;
-
-	cache_rec = mail_cache_lookup(cache, rec, 0);
-	if (cache_rec == NULL)
-		return TRUE;
-
-	/* NOTE: it would be nice to erase the cached data for the record,
-	   but some other processes might still be using them. So, we just
-	   update the deleted_space in header */
-	deleted_space = nbo_to_uint32(cache->header->deleted_space);
-
-	do {
-		deleted_space -= nbo_to_uint32(cache_rec->size);
-		cache_rec = cache_get_next_record(cache, cache_rec);
-	} while (cache_rec != NULL);
-
-	/* see if we've reached the max. deleted space in file */
-	max_del_space = cache->used_file_size / 100 * COMPRESS_PERCENTAGE;
-	if (deleted_space >= max_del_space &&
-	    cache->used_file_size >= COMPRESS_MIN_SIZE)
-		cache->index->set_flags |= MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
-
-	cache->header->deleted_space = uint32_to_nbo(deleted_space);
-
-	return TRUE;
-}
-
-enum mail_cache_field
-mail_cache_get_fields(struct mail_cache *cache,
-		      const struct mail_index_record *rec)
-{
-	struct mail_cache_record *cache_rec;
-        enum mail_cache_field fields = 0;
-
-	cache_rec = mail_cache_lookup(cache, rec, 0);
-	while (cache_rec != NULL) {
-		fields |= cache_rec->fields;
-		cache_rec = cache_get_next_record(cache, cache_rec);
-	}
-
-	return fields;
-}
-
-static int cache_get_field(struct mail_cache *cache,
-			   struct mail_cache_record *cache_rec,
-			   enum mail_cache_field field,
-			   void **data_r, size_t *size_r)
-{
-	unsigned char *buf;
-	unsigned int mask;
-	uint32_t rec_size, data_size;
-	size_t offset, next_offset;
-	int i;
-
-	rec_size = nbo_to_uint32(cache_rec->size);
-	buf = (unsigned char *) cache_rec;
-	offset = sizeof(*cache_rec);
-
-	for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
-		if ((cache_rec->fields & mask) == 0)
-			continue;
-
-		/* all records are at least 32bit. we have to check this
-		   before getting data_size. */
-		if (offset + sizeof(uint32_t) > rec_size) {
-			mail_cache_set_corrupted(cache,
-				"Record continues outside it's allocated size");
-			return FALSE;
-		}
-
-		if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
-			data_size = mail_cache_field_sizes[i];
-		else {
-			memcpy(&data_size, buf + offset, sizeof(data_size));
-			data_size = nbo_to_uint32(data_size);
-			offset += sizeof(data_size);
-		}
-
-		next_offset = offset + ((data_size + 3) & ~3);
-		if (next_offset > rec_size) {
-			mail_cache_set_corrupted(cache,
-				"Record continues outside it's allocated size");
-			return FALSE;
-		}
-
-		if (field == mask) {
-			if (data_size == 0) {
-				mail_cache_set_corrupted(cache,
-							 "Field size is 0");
-				return FALSE;
-			}
-			*data_r = buf + offset;
-			*size_r = data_size;
-			return TRUE;
-		}
-		offset = next_offset;
-	}
-
-	i_unreached();
-	return FALSE;
-}
-
-static int cache_lookup_field(struct mail_cache *cache,
-			      const struct mail_index_record *rec,
-			      enum mail_cache_field field,
-			      void **data_r, size_t *size_r)
-{
-	struct mail_cache_record *cache_rec;
-
-	cache_rec = mail_cache_lookup(cache, rec, field);
-	while (cache_rec != NULL) {
-		if ((cache_rec->fields & field) != 0) {
-			return cache_get_field(cache, cache_rec, field,
-					       data_r, size_r);
-		}
-		cache_rec = cache_get_next_record(cache, cache_rec);
-	}
-
-	return FALSE;
-}
-
-int mail_cache_lookup_field(struct mail_cache *cache,
-			    const struct mail_index_record *rec,
-			    enum mail_cache_field field,
-			    const void **data_r, size_t *size_r)
-{
-	void *data;
-
-	if (!cache_lookup_field(cache, rec, field, &data, size_r))
-		return FALSE;
-
-	*data_r = data;
-	return TRUE;
-}
-
-const char *mail_cache_lookup_string_field(struct mail_cache *cache,
-					   const struct mail_index_record *rec,
-					   enum mail_cache_field field)
-{
-	const void *data;
-	size_t size;
-
-	i_assert((field & MAIL_CACHE_STRING_MASK) != 0);
-
-	if (!mail_cache_lookup_field(cache, rec, field, &data, &size))
-		return NULL;
-
-	if (((const char *) data)[size-1] != '\0') {
-		mail_cache_set_corrupted(cache,
-			"String field %x doesn't end with NUL", field);
-		return NULL;
-	}
-	return data;
-}
-
-int mail_cache_copy_fixed_field(struct mail_cache *cache,
-				const struct mail_index_record *rec,
-				enum mail_cache_field field,
-				void *buffer, size_t buffer_size)
-{
-	const void *data;
-	size_t size;
-
-	i_assert((field & MAIL_CACHE_FIXED_MASK) != 0);
-
-	if (!mail_cache_lookup_field(cache, rec, field, &data, &size))
-		return FALSE;
-
-	if (buffer_size != size) {
-		i_panic("cache: fixed field %x wrong size "
-			"(%"PRIuSIZE_T" vs %"PRIuSIZE_T")",
-			field, size, buffer_size);
-	}
-
-	memcpy(buffer, data, buffer_size);
-	return TRUE;
-}
-
-void mail_cache_mark_missing(struct mail_cache *cache,
-			     enum mail_cache_field fields)
-{
-	// FIXME: count these
-}
-
-enum mail_index_record_flag
-mail_cache_get_index_flags(struct mail_cache *cache,
-			   const struct mail_index_record *rec)
-{
-	enum mail_index_record_flag flags;
-
-	if (!mail_cache_copy_fixed_field(cache, rec, MAIL_CACHE_INDEX_FLAGS,
-					 &flags, sizeof(flags)))
-		return 0;
-
-	return flags;
-}
-
-int mail_cache_update_index_flags(struct mail_cache *cache,
-				  struct mail_index_record *rec,
-				  enum mail_index_record_flag flags)
-{
-	void *data;
-	size_t size;
-
-	i_assert(cache->locks > 0);
-
-	if (!cache_lookup_field(cache, rec, MAIL_CACHE_INDEX_FLAGS,
-				&data, &size)) {
-		mail_cache_set_corrupted(cache,
-			"Missing index flags for record %u", rec->uid);
-		return FALSE;
-	}
-
-	memcpy(data, &flags, sizeof(flags));
-	return TRUE;
-}
-
-int mail_cache_update_location_offset(struct mail_cache *cache,
-				      struct mail_index_record *rec,
-				      uoff_t offset)
-{
-	void *data;
-	size_t size;
-
-	i_assert(cache->locks > 0);
-
-	if (!cache_lookup_field(cache, rec, MAIL_CACHE_LOCATION_OFFSET,
-				&data, &size)) {
-		mail_cache_set_corrupted(cache,
-			"Missing location offset for record %u", rec->uid);
-		return FALSE;
-	}
-
-	memcpy(data, &offset, sizeof(offset));
-	return TRUE;
-}
-
-void *mail_cache_get_mmaped(struct mail_cache *cache, size_t *size)
-{
-	if (!mmap_update(cache, 0, 0))
-		return NULL;
-
-	*size = cache->mmap_length;
-	return cache->mmap_base;
-}
-
-int mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
-{
-	va_list va;
-
-	mail_cache_mark_file_deleted(cache);
-	cache->index->inconsistent = TRUE; /* easiest way to rebuild */
-
-	if (cache->silent)
-		return FALSE;
-
-	va_start(va, fmt);
-	t_push();
-	index_set_error(cache->index, "Corrupted index cache file %s: %s",
-			cache->filepath, t_strdup_vprintf(fmt, va));
-	t_pop();
-	va_end(va);
-
-	return FALSE;
-}
--- a/src/lib-index/mail-cache.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-#ifndef __MAIL_CACHE_H
-#define __MAIL_CACHE_H
-
-#include "mail-index.h"
-
-#define MAIL_CACHE_FILE_PREFIX ".cache"
-
-#define MAIL_CACHE_HEADERS_COUNT 4
-
-struct mail_cache_transaction_ctx;
-
-enum mail_cache_field {
-	/* fixed size fields */
-	MAIL_CACHE_INDEX_FLAGS		= 0x00000001,
-	MAIL_CACHE_LOCATION_OFFSET	= 0x00000002,
-	MAIL_CACHE_MD5			= 0x00000004,
-	MAIL_CACHE_SENT_DATE		= 0x00000008,
-	MAIL_CACHE_RECEIVED_DATE	= 0x00000010,
-	MAIL_CACHE_VIRTUAL_FULL_SIZE	= 0x00000020,
-	MAIL_CACHE_PHYSICAL_BODY_SIZE	= 0x00000040,
-
-	/* variable sized field */
-	MAIL_CACHE_HEADERS1		= 0x40000000,
-	MAIL_CACHE_HEADERS2		= 0x20000000,
-	MAIL_CACHE_HEADERS3		= 0x10000000,
-	MAIL_CACHE_HEADERS4		= 0x08000000,
-	MAIL_CACHE_LOCATION		= 0x04000000,
-	MAIL_CACHE_BODY			= 0x02000000,
-	MAIL_CACHE_BODYSTRUCTURE	= 0x01000000,
-	MAIL_CACHE_ENVELOPE		= 0x00800000,
-	MAIL_CACHE_MESSAGEPART		= 0x00400000,
-
-	MAIL_CACHE_FIXED_MASK		= MAIL_CACHE_INDEX_FLAGS |
-					  MAIL_CACHE_LOCATION_OFFSET |
-					  MAIL_CACHE_MD5 |
-					  MAIL_CACHE_SENT_DATE |
-					  MAIL_CACHE_RECEIVED_DATE |
-					  MAIL_CACHE_VIRTUAL_FULL_SIZE |
-					  MAIL_CACHE_PHYSICAL_BODY_SIZE,
-	MAIL_CACHE_HEADERS_MASK		= MAIL_CACHE_HEADERS1 |
-					  MAIL_CACHE_HEADERS2 |
-					  MAIL_CACHE_HEADERS3 |
-					  MAIL_CACHE_HEADERS4,
-	MAIL_CACHE_STRING_MASK		= MAIL_CACHE_HEADERS_MASK |
-					  MAIL_CACHE_LOCATION |
-					  MAIL_CACHE_BODY |
-					  MAIL_CACHE_BODYSTRUCTURE |
-					  MAIL_CACHE_ENVELOPE,
-	MAIL_CACHE_BODYSTRUCTURE_MASK	= MAIL_CACHE_BODY |
-					  MAIL_CACHE_BODYSTRUCTURE |
-                                          MAIL_CACHE_MESSAGEPART
-};
-
-struct mail_sent_date {
-	time_t time;
-	int32_t timezone;
-};
-
-extern enum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT];
-
-int mail_cache_open_or_create(struct mail_index *index);
-void mail_cache_free(struct mail_cache *cache);
-
-void mail_cache_set_defaults(struct mail_cache *cache,
-			     enum mail_cache_field default_cache_fields,
-			     enum mail_cache_field never_cache_fields);
-
-/* Compress cache file. */
-int mail_cache_compress(struct mail_cache *cache);
-
-/* Truncate the cache file and update it's indexid */
-int mail_cache_truncate(struct mail_cache *cache);
-
-/* Set indexid to 0 to notify other processes using this file that they should
-   re-open it. */
-int mail_cache_mark_file_deleted(struct mail_cache *cache);
-
-/* Explicitly lock the cache file. Returns 1 if ok, 0 if nonblock is TRUE and
-   we couldn't immediately get a lock, or -1 if error. */
-int mail_cache_lock(struct mail_cache *cache, int nonblock);
-int mail_cache_unlock(struct mail_cache *cache);
-
-/* Mark the lock to be removed when unlocking index file. */
-void mail_cache_unlock_later(struct mail_cache *cache);
-
-/* Returns TRUE if cache file is locked. */
-int mail_cache_is_locked(struct mail_cache *cache);
-
-/* Begin transaction. Returns same as mail_cache_lock(). Note that if you
-   call lookup functions for messages within first and last message in
-   transaction, the transaction will be automatically committed. */
-int mail_cache_transaction_begin(struct mail_cache *cache, int nonblock,
-				 struct mail_cache_transaction_ctx **ctx_r);
-/* End transaction. Single transaction can have multiple commits/rollbacks.
-   If there's any pending changes, they will be rolled back. */
-int mail_cache_transaction_end(struct mail_cache_transaction_ctx *ctx);
-
-int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx);
-int mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx);
-
-/* Return NULL-terminated list of headers for given index, or NULL if
-   header index isn't used. */
-const char *const *mail_cache_get_header_fields(struct mail_cache *cache,
-						unsigned int idx);
-/* Set list of headers for given index. */
-int mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
-				 unsigned int idx, const char *const headers[]);
-
-/* Add new field to given record. Updates are not allowed. Fixed size fields
-   must be exactly the expected size and they're converted to network byte
-   order in disk. */
-int mail_cache_add(struct mail_cache_transaction_ctx *ctx,
-		   struct mail_index_record *rec, enum mail_cache_field field,
-		   const void *data, size_t data_size);
-
-/* Mark the given record deleted. */
-int mail_cache_delete(struct mail_cache_transaction_ctx *ctx,
-		      struct mail_index_record *rec);
-
-/* Return all fields that are currently cached for record. */
-enum mail_cache_field
-mail_cache_get_fields(struct mail_cache *cache,
-		      const struct mail_index_record *rec);
-
-/* Set data_r and size_r to point to wanted field in cache file.
-   Returns TRUE if field was found. If field contains multiple fields,
-   first one found is returned. This is mostly useful for finding headers. */
-int mail_cache_lookup_field(struct mail_cache *cache,
-			    const struct mail_index_record *rec,
-			    enum mail_cache_field field,
-			    const void **data_r, size_t *size_r);
-
-/* Return string field. */
-const char *mail_cache_lookup_string_field(struct mail_cache *cache,
-					   const struct mail_index_record *rec,
-					   enum mail_cache_field field);
-
-
-/* Copy fixed size field to given buffer. buffer_size must be exactly the
-   expected size. The result will be converted to host byte order.
-   Returns TRUE if field was found. */
-int mail_cache_copy_fixed_field(struct mail_cache *cache,
-				const struct mail_index_record *rec,
-				enum mail_cache_field field,
-				void *buffer, size_t buffer_size);
-
-/* Mark given fields as missing, ie. they should be cached when possible. */
-void mail_cache_mark_missing(struct mail_cache *cache,
-			     enum mail_cache_field fields);
-
-/* Return index flags. */
-enum mail_index_record_flag
-mail_cache_get_index_flags(struct mail_cache *cache,
-			   const struct mail_index_record *rec);
-
-/* Update index flags. The cache file must be locked and the flags must be
-   already inserted to the record. */
-int mail_cache_update_index_flags(struct mail_cache *cache,
-				  struct mail_index_record *rec,
-				  enum mail_index_record_flag flags);
-
-/* Update location offset. External locking is assumed to take care of locking
-   readers out to prevent race conditions. */
-int mail_cache_update_location_offset(struct mail_cache *cache,
-				      struct mail_index_record *rec,
-				      uoff_t offset);
-
-/* Return the whole file mmaped. */
-void *mail_cache_get_mmaped(struct mail_cache *cache, size_t *size);
-
-/* "Error in index cache file %s: ...". */
-int mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
-	__attr_format__(2, 3);
-
-#endif
--- a/src/lib-index/mail-custom-flags.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,592 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "file-lock.h"
-#include "mmap-util.h"
-#include "write-full.h"
-#include "imap-util.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-custom-flags.h"
-
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-/* Header is simply a counter which is increased every time the file is
-   updated. This allows other processes to easily notice if there's been
-   any changes. */
-
-#define COUNTER_SIZE 4
-#define HEADER_SIZE (COUNTER_SIZE + 1) /* 0000\n */
-
-struct mail_custom_flags {
-	struct mail_index *index;
-	char *filepath;
-	int fd;
-	int lock_type;
-
-	char sync_counter[COUNTER_SIZE];
-	char *custom_flags[MAIL_CUSTOM_FLAGS_COUNT];
-
-	void *mmap_base;
-	size_t mmap_length;
-
-	unsigned int syncing:1;
-	unsigned int noupdate:1;
-	unsigned int changed:1;
-};
-
-static int lock_file(struct mail_custom_flags *mcf, int type);
-
-static int index_cf_set_syscall_error(struct mail_custom_flags *mcf,
-				      const char *function)
-{
-	i_assert(function != NULL);
-
-	if (ENOSPACE(errno)) {
-		mcf->index->nodiskspace = TRUE;
-		return FALSE;
-	}
-
-	index_set_error(mcf->index, "%s failed with custom flags file %s: %m",
-			function, mcf->filepath);
-	return FALSE;
-}
-
-static int update_mmap(struct mail_custom_flags *mcf)
-{
-	if (mcf->mmap_base != NULL) {
-		if (munmap(mcf->mmap_base, mcf->mmap_length) < 0)
-			index_cf_set_syscall_error(mcf, "munmap()");
-	}
-
-
-	mcf->mmap_base = mcf->noupdate ?
-		mmap_ro_file(mcf->fd, &mcf->mmap_length) :
-		mmap_rw_file(mcf->fd, &mcf->mmap_length);
-	if (mcf->mmap_base == MAP_FAILED) {
-		mcf->mmap_base = NULL;
-		return index_cf_set_syscall_error(mcf, "mmap()");
-	}
-
-	(void)madvise(mcf->mmap_base, mcf->mmap_length, MADV_SEQUENTIAL);
-	return TRUE;
-}
-
-static int custom_flags_init(struct mail_custom_flags *mcf)
-{
-	static char buf[HEADER_SIZE] = "0000\n";
-	struct stat st;
-	int failed;
-
-	if (!lock_file(mcf, F_WRLCK))
-		return FALSE;
-
-	failed = FALSE;
-
-	/* make sure it's still empty after locking */
-	if (fstat(mcf->fd, &st) < 0) {
-		index_cf_set_syscall_error(mcf, "fstat()");
-		failed = TRUE;
-	} else if (st.st_size < HEADER_SIZE) {
-		/* write the header - it's a 4 byte counter as hex */
-		if (write_full(mcf->fd, buf, HEADER_SIZE) < 0) {
-			index_cf_set_syscall_error(mcf, "write_full()");
-			failed = TRUE;
-		}
-	}
-
-	if (!lock_file(mcf, F_UNLCK))
-		return FALSE;
-
-	return !failed;
-}
-
-static void custom_flags_sync(struct mail_custom_flags *mcf)
-{
-	char *data, *data_end, *line;
-	unsigned int num;
-	int i;
-
-	if (mcf->noupdate)
-		return;
-
-	memcpy(mcf->sync_counter, mcf->mmap_base, COUNTER_SIZE);
-
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-		if (mcf->custom_flags[i] != NULL) {
-			i_free(mcf->custom_flags[i]);
-                        mcf->custom_flags[i] = NULL;
-		}
-	}
-
-	data = mcf->mmap_base;
-	data_end = data + mcf->mmap_length;
-
-	/* this loop skips the first line, which is the header */
-	while (data != data_end) {
-		if (*data != '\n') {
-			data++;
-			continue;
-		}
-
-		/* beginning of line, get the index */
-		if (data+1 == data_end)
-			break;
-		data++;
-
-		if (!i_isdigit(*data))
-			continue;
-
-		num = 0;
-		while (data != data_end && *data >= '0' && *data <= '9') {
-			num = num*10 + (*data-'0');
-			data++;
-		}
-
-		if (num < MAIL_CUSTOM_FLAGS_COUNT) {
-			/* get the name */
-			if (data == data_end || *data != ' ')
-				continue;
-
-			line = ++data;
-			while (data != data_end && *data != '\n')
-				data++;
-
-			if (mcf->custom_flags[num] != NULL) {
-				i_warning("Error in custom flags file %s: "
-					  "Duplicated ID %u", mcf->filepath,
-					  num);
-				i_free(mcf->custom_flags[num]);
-			}
-
-			mcf->custom_flags[num] = i_strdup_until(line, data);
-		}
-	}
-}
-
-static int custom_flags_check_sync(struct mail_custom_flags *mcf)
-{
-	if (mcf->fd == -1)
-		return TRUE;
-
-	if (mcf->mmap_length != 0 &&
-	    memcmp(mcf->sync_counter, mcf->mmap_base, COUNTER_SIZE) == 0)
-		return TRUE;
-
-	/* file modified, resync */
-	if (!update_mmap(mcf))
-		return FALSE;
-
-	if (mcf->mmap_length < HEADER_SIZE && !mcf->noupdate) {
-		/* it's broken, rewrite header */
-		if (mcf->lock_type == F_RDLCK)
-			(void)lock_file(mcf, F_UNLCK);
-
-		if (lseek(mcf->fd, 0, SEEK_SET) < 0) {
-			index_cf_set_syscall_error(mcf, "lseek()");
-			return FALSE;
-		}
-
-		if (!custom_flags_init(mcf))
-			return FALSE;
-
-		if (!update_mmap(mcf))
-			return FALSE;
-	}
-
-	custom_flags_sync(mcf);
-	mcf->changed = TRUE;
-	return TRUE;
-}
-
-static int lock_file(struct mail_custom_flags *mcf, int type)
-{
-	if (mcf->lock_type == type)
-		return TRUE;
-
-	if (mcf->fd != -1) {
-		/* FIXME: possibility to use .lock file instead */
-		if (file_wait_lock(mcf->fd, type) <= 0) {
-			index_cf_set_syscall_error(mcf, "file_wait_lock()");
-			return FALSE;
-		}
-	}
-
-	mcf->lock_type = type;
-
-	if (type != F_UNLCK && !mcf->syncing) {
-		mcf->syncing = TRUE;
-		if (!custom_flags_check_sync(mcf)) {
-			mcf->syncing = FALSE;
-			return FALSE;
-		}
-
-		/* syncing may have changed locking, do it again */
-		if (!lock_file(mcf, type)) {
-			mcf->syncing = FALSE;
-			return FALSE;
-		}
-
-		mcf->syncing = FALSE;
-	}
-	return TRUE;
-}
-
-int mail_custom_flags_open_or_create(struct mail_index *index)
-{
-	struct mail_custom_flags *mcf;
-	const char *path;
-	int fd, readonly;
-
-	readonly = index->mailbox_readonly;
-
-	if (index->control_dir != NULL) {
-		path = t_strconcat(index->control_dir, "/",
-				   CUSTOM_FLAGS_FILE_NAME, NULL);
-		fd = !readonly ? open(path, O_RDWR | O_CREAT, 0660) :
-			open(path, O_RDONLY);
-		if (fd == -1 && errno == EACCES) {
-			fd = open(path, O_RDONLY);
-			readonly = TRUE;
-		}
-		if (fd == -1 && errno != EACCES && errno != ENOENT &&
-		    !ENOSPACE(errno)) {
-			index_file_set_syscall_error(index, path, "open()");
-			return FALSE;
-		}
-	} else {
-		path = NULL;
-		fd = -1;
-	}
-
-	mcf = i_new(struct mail_custom_flags, 1);
-	mcf->index = index;
-	mcf->filepath = fd != -1 ? i_strdup(path) :
-		i_strdup_printf("(in-memory custom flags for %s)",
-				index->mailbox_path);
-	mcf->fd = fd;
-	mcf->noupdate = mcf->fd == -1 || readonly;
-
-	if (fd != -1) {
-		if (!update_mmap(mcf)) {
-			(void)close(mcf->fd);
-			mcf->fd = -1;
-			mcf->noupdate = TRUE;
-		}
-
-		if (mcf->mmap_length < HEADER_SIZE && !mcf->noupdate) {
-			/* we just created it, write the header */
-			mcf->syncing = TRUE;
-			if (!custom_flags_init(mcf) || !update_mmap(mcf)) {
-				(void)close(mcf->fd);
-				mcf->fd = -1;
-				mcf->noupdate = TRUE;
-			}
-			mcf->syncing = FALSE;
-		}
-	}
-
-	mcf->index->allow_new_custom_flags = mcf->fd != -1;
-
-	custom_flags_sync(mcf);
-
-	index->custom_flags = mcf;
-	return TRUE;
-}
-
-void mail_custom_flags_free(struct mail_custom_flags *mcf)
-{
-	int i;
-
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++)
-		i_free(mcf->custom_flags[i]);
-
-	if (mcf->mmap_base != NULL) {
-		if (munmap(mcf->mmap_base, mcf->mmap_length) < 0)
-			index_cf_set_syscall_error(mcf, "munmap()");
-	}
-
-	if (mcf->fd != -1) {
-		if (close(mcf->fd) < 0)
-			index_cf_set_syscall_error(mcf, "close()");
-	}
-
-	i_free(mcf->filepath);
-	i_free(mcf);
-}
-
-static int custom_flags_update_counter(struct mail_custom_flags *mcf)
-{
-	int i;
-
-	if (lseek(mcf->fd, 0, SEEK_SET) < 0)
-		return index_cf_set_syscall_error(mcf, "lseek()");
-
-	for (i = COUNTER_SIZE-1; i >= 0; i--) {
-		if (mcf->sync_counter[i] == '9') {
-			mcf->sync_counter[i] = 'A';
-			break;
-		}
-
-		if (mcf->sync_counter[i] == 'F') {
-			/* digit wrapped, update next one */
-			mcf->sync_counter[i] = '0';
-		} else {
-			mcf->sync_counter[i]++;
-			break;
-		}
-	}
-
-	if (write_full(mcf->fd, mcf->sync_counter, COUNTER_SIZE) < 0)
-		return index_cf_set_syscall_error(mcf, "write_full()");
-
-	mcf->changed = TRUE;
-	return TRUE;
-}
-
-static int custom_flags_add(struct mail_custom_flags *mcf,
-			    int idx, const char *name)
-{
-	const char *buf;
-	size_t len;
-	off_t pos;
-
-	i_assert(idx < MAIL_CUSTOM_FLAGS_COUNT);
-
-	/* first update the sync counter */
-	if (!custom_flags_update_counter(mcf))
-		return FALSE;
-
-	/* add the flag */
-	pos = lseek(mcf->fd, 0, SEEK_END);
-	if (pos < 0)
-		return index_cf_set_syscall_error(mcf, "lseek()");
-
-	if (pos != (off_t)mcf->mmap_length) {
-		index_set_error(mcf->index, "Custom flags file %s was "
-				"changed by someone while we were"
-				"trying to modify it", mcf->filepath);
-		return FALSE;
-	}
-
-	buf = t_strdup_printf("\n%d %s\n", idx, name);
-	len = strlen(buf);
-
-	if (((char *) mcf->mmap_base)[mcf->mmap_length-1] == '\n') {
-		/* don't add the \n prefix */
-		buf++;
-		len--;
-	}
-
-	if (write_full(mcf->fd, buf, len) < 0)
-		return index_cf_set_syscall_error(mcf, "write_full()");
-
-	if (!update_mmap(mcf))
-		return FALSE;
-
-	return TRUE;
-}
-
-static int custom_flags_remove(struct mail_custom_flags *mcf, unsigned int idx)
-{
-	char *data, *data_end, *line;
-	unsigned int num;
-	int pos, linelen;
-
-	data = mcf->mmap_base;
-	data_end = data + mcf->mmap_length;
-
-	while (data != data_end) {
-		if (*data != '\n') {
-			data++;
-			continue;
-		}
-
-		/* beginning of line, get the index */
-		if (data+1 == data_end)
-			break;
-		line = ++data;
-
-		num = 0;
-		while (data != data_end && *data >= '0' && *data <= '9') {
-			num = num*10 + (*data-'0');
-			data++;
-		}
-
-		if (num == idx) {
-			/* remove this line */
-			while (data != data_end && data[-1] != '\n')
-				data++;
-
-			linelen = (int) (data - line);
-			pos = (int) (data - (char *) mcf->mmap_base);
-			memmove(line, data, mcf->mmap_length - pos);
-
-			mcf->mmap_length -= linelen;
-			if (ftruncate(mcf->fd, (off_t) mcf->mmap_length) < 0) {
-				index_cf_set_syscall_error(mcf, "ftruncate()");
-				return FALSE;
-			}
-
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
-static int find_first_unused_flag(struct mail_custom_flags *mcf)
-{
-	int i;
-
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-		if (mcf->custom_flags[i] == NULL)
-			return i;
-	}
-
-	return -1;
-}
-
-static void remove_unused_custom_flags(struct mail_custom_flags *mcf,
-				       enum mail_flags used_flags)
-{
-	unsigned int i;
-
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-		if ((used_flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT))) == 0) {
-			i_free(mcf->custom_flags[i]);
-			mcf->custom_flags[i] = NULL;
-
-			custom_flags_remove(mcf, i);
-		}
-	}
-}
-
-static enum mail_flags get_used_flags(struct mail_custom_flags *mcf)
-{
-	struct mail_index_record *rec;
-	enum mail_flags used_flags;
-
-	used_flags = 0;
-
-	rec = mcf->index->lookup(mcf->index, 1);
-	while (rec != NULL) {
-		used_flags |= rec->msg_flags;
-		rec = mcf->index->next(mcf->index, rec);
-	}
-
-	return used_flags;
-}
-
-static int get_flag_index(struct mail_custom_flags *mcf, const char *flag,
-			  int index_hint)
-{
-	int i, first_empty;
-
-	if (index_hint >= 0 && index_hint < MAIL_CUSTOM_FLAGS_COUNT) {
-		if (mcf->custom_flags[index_hint] != NULL &&
-		    strcasecmp(mcf->custom_flags[index_hint], flag) == 0)
-			return index_hint;
-	}
-
-	/* check existing flags */
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-		if (mcf->custom_flags[i] != NULL) {
-			i_assert(mcf->custom_flags[i] != '\0');
-			if (strcasecmp(mcf->custom_flags[i], flag) == 0)
-				return i;
-		}
-	}
-
-	if (mcf->noupdate)
-		return -1;
-
-	if (mcf->lock_type != F_WRLCK) {
-		/* unlock + write lock, don't directly change from
-		   read -> write lock to prevent deadlocking */
-		if (!lock_file(mcf, F_UNLCK) || !lock_file(mcf, F_WRLCK))
-			return -1;
-
-		/* list may have already changed between the lock changes,
-		   check again */
-		return get_flag_index(mcf, flag, -1);
-	}
-
-	/* new flag, add it. first find the first free flag, note that
-	   unlock+lock might have just changed it. */
-	first_empty = find_first_unused_flag(mcf);
-	if (first_empty == -1) {
-		/* all custom flags are used, see if some of them are unused */
-		remove_unused_custom_flags(mcf, get_used_flags(mcf));
-
-		first_empty = find_first_unused_flag(mcf);
-		if (first_empty == -1) {
-			/* everything is in use */
-			return -1;
-		}
-	}
-
-	if (!custom_flags_add(mcf, first_empty, flag))
-		return -1;
-
-	mcf->index->set_flags |= MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS;
-
-	mcf->custom_flags[first_empty] = i_strdup(flag);
-	return first_empty;
-}
-
-int mail_custom_flags_fix_list(struct mail_custom_flags *mcf,
-			       enum mail_flags *flags,
-			       const char *custom_flags[], unsigned int count)
-{
-	enum mail_flags oldflags, flag;
-	int i, idx;
-
-	i_assert(count < 32);
-
-	if ((*flags & MAIL_CUSTOM_FLAGS_MASK) == 0)
-		return 1;
-
-	if (!lock_file(mcf, F_RDLCK))
-		return -1;
-
-	oldflags = *flags;
-	*flags &= MAIL_SYSTEM_FLAGS_MASK;
-
-	flag = MAIL_CUSTOM_FLAG_1;
-	for (i = 0; i < (int)count; i++, flag <<= 1) {
-		if ((oldflags & flag) && custom_flags[i] != NULL) {
-			i_assert(*custom_flags[i] != '\0');
-
-			idx = get_flag_index(mcf, custom_flags[i], i);
-			if (idx == -1) {
-				(void)lock_file(mcf, F_UNLCK);
-				return 0;
-			}
-			*flags |= 1 << (idx + MAIL_CUSTOM_FLAG_1_BIT);
-		}
-	}
-
-	if (!lock_file(mcf, F_UNLCK))
-		return -1;
-
-	return 1;
-}
-
-const char **mail_custom_flags_list_get(struct mail_custom_flags *mcf)
-{
-	return (const char **) mcf->custom_flags;
-}
-
-int mail_custom_flags_has_changes(struct mail_custom_flags *mcf)
-{
-	if (!mcf->changed)
-		return FALSE;
-	else {
-		mcf->changed = FALSE;
-		return TRUE;
-	}
-}
--- a/src/lib-index/mail-custom-flags.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#ifndef __MAIL_CUSTOM_FLAGS_H
-#define __MAIL_CUSTOM_FLAGS_H
-
-/* NOTE: Contains it's own locking, unrelated to index locks. */
-
-#include "mail-index.h"
-
-#define CUSTOM_FLAGS_FILE_NAME ".customflags"
-
-int mail_custom_flags_open_or_create(struct mail_index *index);
-void mail_custom_flags_free(struct mail_custom_flags *mcf);
-
-/* Change custom flags so that they reflect the real flag numbers in
-   the file. Initially flags contains the custom flags in the order of the
-   specified list, it's modified to reflect the actual list. Returns 1 if ok,
-   0 if number of custom flags exceeded or -1 if error */
-int mail_custom_flags_fix_list(struct mail_custom_flags *mcf,
-			       enum mail_flags *flags,
-			       const char *custom_flags[], unsigned int count);
-
-/* Returns a pointer to list of flags. Note that calls to
-   mail_cutom_flags_fix_list() may modify the flags in the returned list.
-   It can modify only the flags that aren't in use anywhere, so this should
-   be safe. */
-const char **mail_custom_flags_list_get(struct mail_custom_flags *mcf);
-
-/* Returns TRUE if there's been any changes since this function was
-   called last time, or since open if this is the first call. */
-int mail_custom_flags_has_changes(struct mail_custom_flags *mcf);
-
-#endif
--- a/src/lib-index/mail-index-file.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,208 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "file-set-size.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-
-#include <unistd.h>
-
-struct mail_index_record *mail_index_next(struct mail_index *index,
-					  struct mail_index_record *rec)
-{
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-	i_assert(rec >= INDEX_RECORD_AT(index, 0));
-
-	return rec+1 == INDEX_END_RECORD(index) ? NULL : rec+1;
-}
-
-static int compress(struct mail_index *index, unsigned int remove_first_idx,
-		    unsigned int remove_last_idx)
-{
-	struct mail_index_record *rec = INDEX_RECORD_AT(index, 0);
-	unsigned int idx_limit, count;
-
-	idx_limit = MAIL_INDEX_RECORD_COUNT(index);
-	count = remove_last_idx - remove_first_idx + 1;
-
-	memmove(rec + remove_first_idx, rec + remove_last_idx + 1,
-		(idx_limit - remove_last_idx - 1) * sizeof(*rec));
-
-	index->header->used_file_size -= sizeof(*rec) * count;
-	index->mmap_used_length -= sizeof(*rec) * count;
-
-	/* not really needed since append() will initialize it as well,
-	   but may help preventing problems if change is only partially
-	   written to disk */
-	memset((char *) rec + index->mmap_used_length, 0, sizeof(*rec) * count);
-
-	return mail_index_truncate(index);
-}
-
-int mail_index_expunge_record_range(struct mail_index *index,
-				    struct mail_index_record *first_rec,
-				    struct mail_index_record *last_rec)
-{
-	struct mail_index_record *rec;
-	unsigned int first_idx, last_idx, idx_limit;
-
-        i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	first_idx = INDEX_RECORD_INDEX(index, first_rec);
-	last_idx = INDEX_RECORD_INDEX(index, last_rec);
-	idx_limit = MAIL_INDEX_RECORD_COUNT(index);
-
-	i_assert(first_idx <= last_idx);
-	i_assert(last_idx < idx_limit);
-
-	index->header->messages_count -= last_idx - first_idx + 1;
-	for (rec = first_rec; rec <= last_rec; rec++)
-		mail_index_mark_flag_changes(index, rec, rec->msg_flags, 0);
-
-	return compress(index, first_idx, last_idx);
-}
-
-struct mail_index_record *mail_index_lookup(struct mail_index *index,
-					    unsigned int seq)
-{
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-	i_assert(seq > 0);
-
-	if (seq > index->header->messages_count)
-		return NULL;
-
-	return INDEX_RECORD_AT(index, seq-1);
-}
-
-struct mail_index_record *
-mail_index_lookup_uid_range(struct mail_index *index, unsigned int first_uid,
-			    unsigned int last_uid, unsigned int *seq_r)
-{
-	struct mail_index_record *rec_p;
-	unsigned int idx_limit, idx, left_idx, right_idx;
-
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-	i_assert(first_uid > 0);
-	i_assert(first_uid <= last_uid);
-
-	rec_p = INDEX_RECORD_AT(index, 0);
-	idx_limit = MAIL_INDEX_RECORD_COUNT(index);
-
-	idx = 0;
-	left_idx = 0;
-	right_idx = idx_limit;
-
-	while (left_idx < right_idx) {
-		idx = (left_idx + right_idx) / 2;
-
-		if (rec_p[idx].uid < first_uid)
-			left_idx = idx+1;
-		else if (rec_p[idx].uid > first_uid)
-			right_idx = idx;
-		else
-			break;
-	}
-
-	if (rec_p[idx].uid < first_uid || rec_p[idx].uid > last_uid) {
-		/* could still be the next one */
-		idx++;
-		if (idx == idx_limit ||
-		    rec_p[idx].uid < first_uid || rec_p[idx].uid > last_uid) {
-			if (seq_r != NULL) *seq_r = 0;
-			return NULL;
-		}
-	}
-
-	if (seq_r != NULL)
-		*seq_r = idx + 1;
-	return rec_p + idx;
-}
-
-int mail_index_compress(struct mail_index *index)
-{
-	size_t diff;
-	off_t new_file_size;
-
-	if (index->header_size >= sizeof(struct mail_index_header))
-		return TRUE;
-
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	/* make sure the file is large enough */
-	diff = sizeof(struct mail_index_header) - index->header_size;
-	if (index->mmap_used_length + diff > index->mmap_full_length) {
-		/* mmap_update ftruncates the file to multiples of
-		   mail_index_record, make sure we grow it enough here. */
-		new_file_size = index->mmap_used_length + diff +
-			(sizeof(struct mail_index_record) -
-			 (diff % sizeof(struct mail_index_record)));
-		if (file_set_size(index->fd, new_file_size) < 0) {
-			index_set_syscall_error(index, "file_set_size()");
-			return FALSE;
-		}
-
-		index->header->master_sync_id++;
-		if (!mail_index_mmap_update(index))
-			return FALSE;
-	}
-
-	/* if we break, we'll have to rebuild it completely */
-	index->header->flags |= MAIL_INDEX_HDR_FLAG_REBUILD;
-	if (!mail_index_fmdatasync(index, index->header_size))
-		return FALSE;
-
-	memmove((char *) index->mmap_base + sizeof(struct mail_index_header),
-		(char *) index->mmap_base + index->header_size,
-		index->mmap_used_length - index->header_size);
-	memset((char *) index->mmap_base + index->header_size, 0, diff);
-
-	index->mmap_used_length += diff;
-	index->header_size = sizeof(struct mail_index_header);
-
-	index->header->header_size = sizeof(struct mail_index_header);
-	index->header->used_file_size += diff;
-	index->header->master_sync_id++;
- 
-	if (!mail_index_fmdatasync(index, index->mmap_used_length))
-		return FALSE;
-
-	index->header->flags &= ~MAIL_INDEX_HDR_FLAG_REBUILD;
-	return mail_index_mmap_update(index);
-}
-
-int mail_index_truncate(struct mail_index *index)
-{
-	uoff_t empty_space, truncate_threshold;
-
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	if (index->mmap_full_length <= INDEX_FILE_MIN_SIZE(index) ||
-	    index->anon_mmap)
-		return TRUE;
-
-	/* really truncate the file only when it's almost empty */
-	empty_space = index->mmap_full_length - index->mmap_used_length;
-	truncate_threshold =
-		index->mmap_full_length / 100 * INDEX_TRUNCATE_PERCENTAGE;
-
-	if (empty_space > truncate_threshold) {
-		index->mmap_full_length = index->mmap_used_length +
-			(empty_space * INDEX_TRUNCATE_KEEP_PERCENTAGE / 100);
-
-		/* keep the size record-aligned */
-		index->mmap_full_length -= (index->mmap_full_length -
-					    index->header_size) %
-			sizeof(struct mail_index_record);
-
-		if (index->mmap_full_length < INDEX_FILE_MIN_SIZE(index))
-                        index->mmap_full_length = INDEX_FILE_MIN_SIZE(index);
-
-		if (ftruncate(index->fd, (off_t)index->mmap_full_length) < 0)
-			return index_set_syscall_error(index, "ftruncate()");
-
-		index->header->master_sync_id++;
-	}
-
-	return TRUE;
-}
--- a/src/lib-index/mail-index-fsck.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-
-#define CHECK(field) \
-	if (old_hdr->field != new_hdr->field) \
-		i_warning("fsck %s: "#field" %u != %u", \
-			  index->filepath, old_hdr->field, new_hdr->field);
-
-
-static void print_differences(struct mail_index *index,
-			      struct mail_index_header *old_hdr,
-			      struct mail_index_header *new_hdr)
-{
-	CHECK(next_uid);
-
-	CHECK(messages_count);
-	CHECK(seen_messages_count);
-	CHECK(deleted_messages_count);
-	CHECK(last_nonrecent_uid);
-
-	if (old_hdr->first_unseen_uid_lowwater >
-	    new_hdr->first_unseen_uid_lowwater) {
-		i_warning("fsck %s: first_unseen_uid_lowwater %u > %u",
-			  index->filepath,
-			  old_hdr->first_unseen_uid_lowwater,
-                          new_hdr->first_unseen_uid_lowwater);
-	}
-
-	if (old_hdr->first_deleted_uid_lowwater >
-	    new_hdr->first_deleted_uid_lowwater) {
-		i_warning("fsck %s: first_deleted_uid_lowwater %u > %u",
-			  index->filepath,
-			  old_hdr->first_deleted_uid_lowwater,
-                          new_hdr->first_deleted_uid_lowwater);
-	}
-}
-
-int mail_index_fsck(struct mail_index *index)
-{
-	struct mail_index_header old_hdr, *hdr;
-	struct mail_index_record *rec, *end_rec;
-	unsigned int max_uid;
-
-	i_assert(index->lock_type != MAIL_LOCK_SHARED);
-
-	if (!mail_index_compress(index))
-		return FALSE;
-
-	/* then we verify only the fields in the header. other problems will
-	   be noticed and fixed while reading the messages. */
-	hdr = index->header;
-	memcpy(&old_hdr, hdr, sizeof(struct mail_index_header));
-
-	hdr->messages_count = 0;
-	hdr->seen_messages_count = 0;
-	hdr->deleted_messages_count = 0;
-
-	hdr->first_unseen_uid_lowwater = 0;
-	hdr->first_deleted_uid_lowwater = 0;
-
-	rec = INDEX_RECORD_AT(index, 0);
-	end_rec = INDEX_END_RECORD(index);
-
-	max_uid = 0;
-	for (; rec < end_rec; rec++) {
-		if (rec->uid < max_uid) {
-			index_set_corrupted(index, "UIDs are not ordered "
-					    "(%u < %u)", rec->uid, max_uid);
-			return FALSE;
-		}
-		max_uid = rec->uid;
-
-		if (rec->msg_flags & MAIL_SEEN)
-			hdr->seen_messages_count++;
-		else if (hdr->first_unseen_uid_lowwater == 0)
-			hdr->first_unseen_uid_lowwater = rec->uid;
-
-		if (rec->msg_flags & MAIL_DELETED) {
-			if (hdr->first_deleted_uid_lowwater == 0)
-                                hdr->first_deleted_uid_lowwater = rec->uid;
-			hdr->deleted_messages_count++;
-		}
-		hdr->messages_count++;
-	}
-
-	if (hdr->next_uid <= max_uid)
-		hdr->next_uid = max_uid+1;
-	if (hdr->last_nonrecent_uid >= hdr->next_uid)
-		hdr->last_nonrecent_uid = hdr->next_uid-1;
-
-	if (hdr->first_unseen_uid_lowwater == 0)
-		hdr->first_unseen_uid_lowwater = hdr->next_uid;
-	if (hdr->first_deleted_uid_lowwater == 0)
-		hdr->first_deleted_uid_lowwater = hdr->next_uid;
-
-	print_differences(index, &old_hdr, hdr);
-
-	/* FSCK flag is removed automatically by set_lock() */
-	return TRUE;
-}
--- a/src/lib-index/mail-index-open.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,397 +0,0 @@
-/* Copyright (C) 2002-2003 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "file-lock.h"
-#include "file-set-size.h"
-#include "hostpid.h"
-#include "mmap-util.h"
-#include "unlink-lockfiles.h"
-#include "write-full.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-#include "mail-modifylog.h"
-#include "mail-custom-flags.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-static int mail_index_open_init(struct mail_index *index,
-				enum mail_index_open_flags flags)
-{
-	struct mail_index_header *hdr;
-
-	hdr = index->header;
-
-	index->maildir_have_new =
-		(hdr->flags & MAIL_INDEX_FLAG_MAILDIR_NEW) != 0;
-
-	if ((hdr->flags & MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES) != 0)
-		index->next_dirty_flags_flush = ioloop_time;
-
-	/* update \Recent message counters */
-	if ((flags & MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT) != 0 &&
-	    hdr->last_nonrecent_uid != hdr->next_uid-1) {
-		/* keep last_recent_uid to next_uid-1 */
-		if (index->lock_type == MAIL_LOCK_SHARED) {
-			if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-				return FALSE;
-		}
-
-		if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-			return FALSE;
-
-		index->first_recent_uid = index->header->last_nonrecent_uid+1;
-		index->header->last_nonrecent_uid = index->header->next_uid-1;
-	} else {
-		index->first_recent_uid = hdr->last_nonrecent_uid+1;
-	}
-
-	if (hdr->next_uid >= MAX_ALLOWED_UID - 1000) {
-		/* UID values are getting too high, rebuild index */
-		index->set_flags |= MAIL_INDEX_HDR_FLAG_REBUILD;
-	}
-
-	if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
-		/* finally reset the modify log marks, fsck or syncing might
-		   have deleted some messages, and since we're only just
-		   opening the index, there's no need to remember them */
-		if (!mail_modifylog_mark_synced(index->modifylog))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-static int index_open_and_fix(struct mail_index *index,
-			      enum mail_index_open_flags flags)
-{
-	int rebuilt;
-
-	if (index->header_size < sizeof(struct mail_index_header)) {
-		/* upgrading from older index file. */
-		if (!mail_index_compress(index))
-			return FALSE;
-	}
-
-	if (!mail_cache_open_or_create(index))
-		return FALSE;
-
-	/* custom flags file needs to be open before rebuilding index */
-	if (!mail_custom_flags_open_or_create(index))
-		return FALSE;
-
-	if ((index->header->flags & MAIL_INDEX_HDR_FLAG_REBUILD) != 0 ||
-	    (index->set_flags & MAIL_INDEX_HDR_FLAG_REBUILD) != 0) {
-
-		if (!index->rebuild(index))
-			return FALSE;
-
-		if ((index->header->flags & MAIL_INDEX_HDR_FLAG_REBUILD) != 0)
-			return FALSE;
-
-		/* no inconsistency problems since we're still opening
-		   the index */
-		index->inconsistent = FALSE;
-		rebuilt = TRUE;
-	} else {
-		rebuilt = FALSE;
-	}
-
-	if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) {
-		if (!mail_modifylog_open_or_create(index))
-			return FALSE;
-	} else {
-		if (!mail_modifylog_create(index))
-			return FALSE;
-	}
-
-	if (index->header->flags & MAIL_INDEX_HDR_FLAG_FSCK) {
-		/* index needs fscking */
-		if (!index->fsck(index))
-			return FALSE;
-	}
-
-	if (!rebuilt) {
-		/* sync ourself. do it before compression which may happen
-		   as a result of this. */
-		if (!index->sync_and_lock(index, FALSE,
-					  MAIL_LOCK_SHARED, NULL) &&
-		    !index->nodiskspace)
-			return FALSE;
-	}
-
-	/* we never want to keep shared lock if syncing happens to set it.
-	   either exclusive or nothing (NOTE: drop it directly, not through
-	   index->set_lock() so mbox lock won't be affected). */
-	if (index->lock_type == MAIL_LOCK_SHARED) {
-		if (!mail_index_set_lock(index, MAIL_LOCK_UNLOCK))
-			return FALSE;
-	}
-
-	if ((flags & MAIL_INDEX_OPEN_FLAG_FAST) == 0) {
-		if (index->header->flags & MAIL_INDEX_HDR_FLAG_COMPRESS) {
-			/* remove deleted blocks from index file */
-			if (!mail_index_compress(index))
-				return FALSE;
-		}
-
-		if (index->header->flags & MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE) {
-			/* remove unused space from index data file. */
-			if (!mail_cache_compress(index->cache))
-				return FALSE;
-		}
-	}
-
-	if (!mail_index_open_init(index, flags))
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mail_index_read_header(struct mail_index *index,
-				  struct mail_index_header *hdr)
-{
-	ssize_t ret;
-
-	if (lseek(index->fd, 0, SEEK_SET) < 0) {
-		index_set_syscall_error(index, "seek()");
-		return -1;
-	}
-
-	ret = read(index->fd, hdr, sizeof(*hdr));
-	if (ret < 0) {
-		index_set_syscall_error(index, "read()");
-		return -1;
-	}
-
-	if (ret != sizeof(*hdr)) {
-		/* missing data */
-		return 0;
-	}
-
-	return 1;
-}
-
-static int mail_index_init_file(struct mail_index *index,
-				const struct mail_index_header *hdr)
-{
-	uoff_t file_size;
-
-	if (lseek(index->fd, 0, SEEK_SET) < 0) {
-		index_set_syscall_error(index, "lseek()");
-		return FALSE;
-	}
-
-	if (write_full(index->fd, hdr, sizeof(*hdr)) < 0) {
-		index_set_syscall_error(index, "write_full()");
-		return FALSE;
-	}
-
-	file_size = sizeof(*hdr) +
-		INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record);
-	if (file_set_size(index->fd, (off_t)file_size) < 0) {
-		index_set_syscall_error(index, "file_set_size()");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static void get_compat_data(unsigned char compat_data[4])
-{
-#ifndef WORDS_BIGENDIAN
-	compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
-#else
-	compat_data[0] = 0;
-#endif
-	compat_data[1] = sizeof(uoff_t);
-	compat_data[2] = sizeof(time_t);
-	compat_data[3] = 0;
-}
-
-void mail_index_init_header(struct mail_index_header *hdr)
-{
-	i_assert(sizeof(struct mail_index_header) < 256);
-
-	memset(hdr, 0, sizeof(*hdr));
-	hdr->major_version = MAIL_INDEX_MAJOR_VERSION;
-	hdr->minor_version = MAIL_INDEX_MINOR_VERSION;
-	hdr->header_size = (uint8_t)sizeof(struct mail_index_header);
-	get_compat_data(hdr->compat_data);
-
-	hdr->indexid = ioloop_time;
-
-	/* mark the index requiring rebuild - rebuild() removes this flag
-	   when it succeeds */
-	hdr->flags = MAIL_INDEX_HDR_FLAG_REBUILD;
-
-	hdr->used_file_size = sizeof(struct mail_index_header);
-	hdr->uid_validity = ioloop_time;
-	hdr->next_uid = 1;
-}
-
-static void mail_index_cleanup_temp_files(const char *dir)
-{
-	unlink_lockfiles(dir, t_strconcat(".temp.", my_hostname, ".", NULL),
-			 ".temp.", time(NULL) - TEMP_FILE_TIMEOUT);
-}
-
-void mail_index_init(struct mail_index *index, const char *dir)
-{
-	size_t len;
-
-	index->fd = -1;
-
-	if (dir != NULL) {
-		index->dir = i_strdup(dir);
-
-		len = strlen(index->dir);
-		if (index->dir[len-1] == '/')
-			index->dir[len-1] = '\0';
-	}
-
-	index->mail_read_mmaped = getenv("MAIL_READ_MMAPED") != NULL;
-}
-
-static int mail_index_create_memory(struct mail_index *index,
-				    enum mail_index_open_flags flags)
-{
-	if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
-		return FALSE;
-
-	flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
-
-	index->header_size = sizeof(struct mail_index_header);
-	index->mmap_full_length = INDEX_FILE_MIN_SIZE(index);
-	index->mmap_base = mmap_anon(index->mmap_full_length);
-	if (index->mmap_base == MAP_FAILED) {
-		index->mmap_base = NULL;
-		return index_set_error(index, "mmap_anon() failed: %m");
-	}
-
-	mail_index_init_header(index->mmap_base);
-	index->header = index->mmap_base;
-	index->mmap_used_length = index->header->used_file_size;
-
-	index->anon_mmap = TRUE;
-	index->lock_type = MAIL_LOCK_EXCLUSIVE;
-	index->indexid = index->header->indexid;
-	index->filepath = i_strdup_printf("(in-memory index for %s)",
-					  index->mailbox_path);
-
-	if (!index_open_and_fix(index, flags)) {
-		mail_index_close(index);
-		return FALSE;
-	}
-
-	index->opened = TRUE;
-	return TRUE;
-}
-
-static int mail_index_open_index(struct mail_index *index,
-				 enum mail_index_open_flags flags)
-{
-	struct mail_index_header hdr;
-	unsigned char compat_data[4];
-	int ret;
-
-	if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0)
-		index->lock_type = MAIL_LOCK_SHARED;
-	else
-		index->lock_type = MAIL_LOCK_EXCLUSIVE;
-
-	/* if index is being created, we'll wait here until it's finished */
-	if (!mail_index_wait_lock(index, MAIL_LOCK_TO_FLOCK(index->lock_type)))
-		return FALSE;
-#ifdef DEBUG
-	if (index->mmap_base != NULL) {
-		mprotect(index->mmap_base, index->mmap_used_length,
-			 PROT_READ|PROT_WRITE);
-	}
-#endif
-
-	if ((ret = mail_index_read_header(index, &hdr)) < 0)
-		return FALSE;
-	index->indexid = hdr.indexid;
-
-	get_compat_data(compat_data);
-	if (ret == 0 || hdr.major_version != MAIL_INDEX_MAJOR_VERSION ||
-	    (hdr.flags & MAIL_INDEX_HDR_FLAG_REBUILD) != 0 ||
-	    memcmp(compat_data, hdr.compat_data, sizeof(compat_data)) != 0 ||
-	    !mail_index_mmap_update(index)) {
-		if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
-			return FALSE;
-
-		flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
-
-		/* so, we're creating the index */
-		if (index->lock_type != MAIL_LOCK_EXCLUSIVE) {
-			/* have to get exclusive lock first */
-			if (!mail_index_wait_lock(index, F_UNLCK))
-				return FALSE;
-			return mail_index_open_index(index, flags);
-		}
-
-		mail_index_init_header(&hdr);
-		if (!mail_index_init_file(index, &hdr))
-			return FALSE;
-
-		if (!mail_index_mmap_update(index))
-			return FALSE;
-	}
-
-	if (index->lock_type == MAIL_LOCK_SHARED) {
-		/* we don't want to keep the shared lock while opening
-		   indexes. opening should work unlocked and some
-		   things want exclusive lock */
-		if (!mail_index_wait_lock(index, F_UNLCK))
-			return FALSE;
-		index->lock_type = MAIL_LOCK_UNLOCK;
-	}
-
-	if (!index_open_and_fix(index, flags))
-		return FALSE;
-
-	if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-		return FALSE;
-
-	index->opened = TRUE;
-	return TRUE;
-}
-
-int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
-{
-	const char *path;
-
-	i_assert(!index->opened);
-
-	if (index->dir == NULL)
-		return mail_index_create_memory(index, flags);
-
-	mail_index_cleanup_temp_files(index->dir);
-
-	/* open/create the file */
-        path = t_strconcat(index->dir, "/", INDEX_FILE_PREFIX, NULL);
-	if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) != 0)
-		index->fd = open(path, O_RDWR | O_CREAT, 0660);
-	else
-		index->fd = open(path, O_RDWR);
-	if (index->fd == -1) {
-		if (errno != ENOENT)
-			index_file_set_syscall_error(index, path, "open()");
-		return mail_index_create_memory(index, flags);
-	}
-
-	index->filepath = i_strdup(path);
-
-	if (!mail_index_open_index(index, flags)) {
-		mail_index_close(index);
-		return mail_index_create_memory(index, flags);
-	}
-
-	return TRUE;
-}
--- a/src/lib-index/mail-index-rebuild.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/* Copyright (C) 2002-2003 Timo Sirainen */
-
-#include "lib.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <sys/mman.h>
-
-int mail_index_rebuild(struct mail_index *index)
-{
-	if (!mail_index_set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	index->set_flags &= ~MAIL_INDEX_HDR_FLAG_REBUILD;
-
-	/* reset the header */
-	mail_index_init_header(index->header);
-	index->mmap_used_length = index->header->used_file_size;
-
-	/* update indexid, which also means that our state has completely
-	   changed */
-	index->indexid = index->header->indexid;
-	index->inconsistent = TRUE;
-	index->rebuilding = TRUE;
-
-	if (!index->anon_mmap) {
-		if (msync(index->mmap_base, index->header_size, MS_SYNC) < 0)
-			return index_set_syscall_error(index, "msync()");
-	}
-
-	if (!mail_cache_truncate(index->cache))
-		return FALSE;
-
-	/* read the mails by syncing */
-	if (!index->sync_and_lock(index, FALSE, MAIL_LOCK_UNLOCK, NULL))
-		return FALSE;
-
-	/* rebuild is complete - remove the flag */
-	index->header->flags &= ~(MAIL_INDEX_HDR_FLAG_REBUILD |
-				  MAIL_INDEX_HDR_FLAG_FSCK);
-	index->header->flags |= index->set_flags;
-	index->set_flags = 0;
-
-	index->rebuilding = FALSE;
-	return TRUE;
-}
--- a/src/lib-index/mail-index-util.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "istream.h"
-#include "hostpid.h"
-#include "file-lock.h"
-#include "message-size.h"
-#include "message-part-serialize.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-int index_set_error(struct mail_index *index, const char *fmt, ...)
-{
-	va_list va;
-
-	i_free(index->error);
-
-	if (fmt == NULL)
-		index->error = NULL;
-	else {
-		va_start(va, fmt);
-		index->error = i_strdup_vprintf(fmt, va);
-		va_end(va);
-
-		i_error("%s", index->error);
-	}
-
-	return FALSE;
-}
-
-int index_set_corrupted(struct mail_index *index, const char *fmt, ...)
-{
-	va_list va;
-
-	INDEX_MARK_CORRUPTED(index);
-	index->inconsistent = TRUE;
-
-	va_start(va, fmt);
-	t_push();
-	index_set_error(index, "Corrupted index file %s: %s",
-			index->filepath, t_strdup_vprintf(fmt, va));
-	t_pop();
-	va_end(va);
-
-	return FALSE;
-}
-
-int index_set_syscall_error(struct mail_index *index, const char *function)
-{
-	i_assert(function != NULL);
-
-	if (ENOSPACE(errno)) {
-		index->nodiskspace = TRUE;
-		return FALSE;
-	}
-
-	index_set_error(index, "%s failed with index file %s: %m",
-			function, index->filepath);
-	return FALSE;
-}
-
-int index_file_set_syscall_error(struct mail_index *index, const char *filepath,
-				 const char *function)
-{
-	i_assert(filepath != NULL);
-	i_assert(function != NULL);
-
-	if (ENOSPACE(errno)) {
-		index->nodiskspace = TRUE;
-		return FALSE;
-	}
-
-	index_set_error(index, "%s failed with file %s: %m",
-			function, filepath);
-
-	return FALSE;
-}
-
-void index_reset_error(struct mail_index *index)
-{
-	if (index->error != NULL) {
-		i_free(index->error);
-		index->error = NULL;
-	}
-
-	index->nodiskspace = FALSE;
-}
-
-int mail_index_create_temp_file(struct mail_index *index, const char **path)
-{
-	int fd;
-
-	/* use ".temp.host.pid" as temporary file name. unlink() it first,
-	   just to be sure it's not symlinked somewhere for some reason..
-	   FIXME: this function should rather be removed entirely. With
-	   in-memory indexes index->dir is NULL, so we fallback to /tmp
-           so that mbox rewriting doesn't crash. */
-	*path = t_strconcat(index->dir != NULL ? index->dir : "/tmp",
-			    "/.temp.", my_hostname, ".", my_pid, NULL);
-	(void)unlink(*path);
-
-	/* usage of O_EXCL isn't exactly needed since the path should be
-	   trusted, but it shouldn't hurt either - if creating file fails
-	   because of it, it's because something must be wrong (race
-	   condition). also, might not won't work through NFS but that
-	   can't be helped. */
-	fd = open(*path, O_RDWR | O_CREAT | O_EXCL, 0660);
-	if (fd == -1) {
-		if (ENOSPACE(errno))
-			index->nodiskspace = TRUE;
-		else {
-			index_set_error(index, "Can't create temp index %s: %m",
-					*path);
-		}
-	}
-
-	return fd;
-}
-
-static void mail_index_lock_notify(unsigned int secs_left, void *context)
-{
-	struct mail_index *index = context;
-
-	if (index->lock_notify_cb == NULL)
-		return;
-
-	index->lock_notify_cb(MAIL_LOCK_NOTIFY_INDEX_ABORT, secs_left,
-			      index->lock_notify_context);
-}
-
-int mail_index_wait_lock(struct mail_index *index, int lock_type)
-{
-	int ret;
-
-	ret = file_wait_lock_full(index->fd, lock_type, DEFAULT_LOCK_TIMEOUT,
-				  mail_index_lock_notify, index);
-	if (ret < 0)
-		return index_set_syscall_error(index, "file_wait_lock()");
-
-	if (ret == 0) {
-		index_set_error(index, "Timeout while waiting for release of "
-				"%s fcntl() lock for index file %s",
-				lock_type == F_WRLCK ? "exclusive" : "shared",
-				index->filepath);
-		index->index_lock_timeout = TRUE;
-		return FALSE;
-	}
-
-	return TRUE;
-
-}
--- a/src/lib-index/mail-index-util.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-#ifndef __MAIL_INDEX_UTIL_H
-#define __MAIL_INDEX_UTIL_H
-
-/* Get index's lock state as mprotect() argument */
-#define MAIL_INDEX_PROT(index) \
-	((index)->lock_type == MAIL_LOCK_EXCLUSIVE ? (PROT_READ|PROT_WRITE) : \
-	 (index)->lock_type == MAIL_LOCK_SHARED || !(index)->opened ? \
-	 PROT_READ : PROT_NONE)
-
-/* DEBUG: Force mmap() locks with mprotect() */
-#ifdef DEBUG
-#  define debug_mprotect(mmap_base, mmap_length, index) \
-	mprotect(mmap_base, mmap_length, MAIL_INDEX_PROT(index))
-#else
-#  define debug_mprotect(mmap_base, mmap_length, index)
-#endif
-
-/* Set the current error message */
-int index_set_error(struct mail_index *index, const char *fmt, ...)
-	__attr_format__(2, 3);
-
-/* "Error in index file %s: ...". Also marks the index file as corrupted. */
-int index_set_corrupted(struct mail_index *index, const char *fmt, ...)
-	__attr_format__(2, 3);
-
-/* "%s failed with index file %s: %m" */
-int index_set_syscall_error(struct mail_index *index, const char *function);
-
-/* "%s failed with file %s: %m" */
-int index_file_set_syscall_error(struct mail_index *index, const char *filepath,
-				 const char *function);
-
-/* Reset the current error */
-void index_reset_error(struct mail_index *index);
-
-/* Create temporary file into index's directory. Returns opened file handle
-   and sets *path to the full path of the created file.  */
-int mail_index_create_temp_file(struct mail_index *index, const char **path);
-
-/* Wrapper to file_set_lock(), also calling index's lock notify callback. */
-int mail_index_wait_lock(struct mail_index *index, int lock_type);
-
-#endif
--- a/src/lib-index/mail-index.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,735 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "file-lock.h"
-#include "file-set-size.h"
-#include "mmap-util.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-#include "mail-modifylog.h"
-#include "mail-custom-flags.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-static void update_header(struct mail_index *index)
-{
-	struct mail_index_header *hdr = index->header;
-
-	index->cache_sync_id = hdr->cache_sync_id;
-	index->log_sync_id = hdr->log_sync_id;
-	index->sync_stamp = hdr->sync_stamp;
-	index->sync_size = hdr->sync_size;
-}
-
-static int mmap_verify(struct mail_index *index)
-{
-	struct mail_index_header *hdr;
-	unsigned int extra;
-
-	index->mmap_used_length = 0;
-
-	if (index->mmap_full_length < sizeof(struct mail_index_header)) {
-                index_set_corrupted(index, "File too small");
-		return FALSE;
-	}
-
-	/* keep the header set even if we fail, so we can update the flags */
-	hdr = index->mmap_base;
-	index->header = hdr;
-	index->header_size = hdr->header_size;
-
-	if (index->header_size > index->mmap_full_length) {
-		index_set_corrupted(index, "Invalid header_size in header "
-				    "(%"PRIuSIZE_T")", index->header_size);
-		return FALSE;
-	}
-
-	extra = (index->mmap_full_length - index->header_size) %
-		sizeof(struct mail_index_record);
-
-	if (extra != 0) {
-		/* partial write or corrupted -
-		   truncate the file to valid length */
-		i_assert(!index->anon_mmap);
-
-		index->mmap_full_length -= extra;
-		(void)ftruncate(index->fd, (off_t)index->mmap_full_length);
-	}
-
-	if (hdr->used_file_size > index->mmap_full_length) {
-		index_set_corrupted(index,
-				    "used_file_size larger than real file size "
-				    "(%u vs %"PRIuSIZE_T")",
-				    hdr->used_file_size,
-				    index->mmap_full_length);
-		return FALSE;
-	}
-
-	if (hdr->used_file_size < index->header_size ||
-	    (hdr->used_file_size - index->header_size) %
-	    sizeof(struct mail_index_record) != 0) {
-		index_set_corrupted(index, "Invalid used_file_size in header "
-				    "(%u)", hdr->used_file_size);
-		return FALSE;
-	}
-
-	if (hdr->messages_count < hdr->seen_messages_count) {
-		index_set_corrupted(index, "Invalid seen messages count "
-				    "(%u < %u)", hdr->messages_count,
-				    hdr->seen_messages_count);
-		return FALSE;
-	}
-
-	if (hdr->messages_count < hdr->deleted_messages_count) {
-		index_set_corrupted(index, "Invalid deleted messages count "
-				    "(%u < %u)", hdr->messages_count,
-				    hdr->deleted_messages_count);
-		return FALSE;
-	}
-
-	index->master_sync_id = hdr->master_sync_id;
-	index->mmap_used_length = hdr->used_file_size;
-        update_header(index);
-	return TRUE;
-}
-
-int mail_index_mmap_update(struct mail_index *index)
-{
-	if (index->anon_mmap)
-		return mmap_verify(index);
-
-	if (index->mmap_base != NULL) {
-		index->header = (struct mail_index_header *) index->mmap_base;
-		update_header(index);
-
-		if (index->mmap_invalidate) {
-			if (msync(index->mmap_base,
-				  index->mmap_used_length,
-				  MS_SYNC | MS_INVALIDATE) < 0) {
-				index_set_syscall_error(index, "msync()");
-				return FALSE;
-			}
-		}
-
-		/* make sure file size hasn't changed */
-		if (index->header->master_sync_id == index->master_sync_id) {
-			index->mmap_used_length = index->header->used_file_size;
-			if (index->mmap_used_length > index->mmap_full_length) {
-				i_panic("Index file size was grown without "
-					"updating sync_id");
-			}
-			return TRUE;
-		}
-
-		if (!index->mmap_invalidate) {
-			if (msync(index->mmap_base,
-				  index->mmap_used_length, MS_SYNC) < 0) {
-				index_set_syscall_error(index, "msync()");
-				return FALSE;
-			}
-		}
-
-		if (munmap(index->mmap_base, index->mmap_full_length) < 0)
-			return index_set_syscall_error(index, "munmap()");
-	}
-
-	index->mmap_base = mmap_rw_file(index->fd, &index->mmap_full_length);
-	if (index->mmap_base == MAP_FAILED) {
-		index->mmap_base = NULL;
-		index->mmap_used_length = 0;
-		index_set_syscall_error(index, "mmap()");
-		return FALSE;
-	}
-
-	return mmap_verify(index);
-}
-
-void mail_index_close(struct mail_index *index)
-{
-	if (index->set_flags != 0) {
-		if (index->header != NULL) {
-#ifdef DEBUG
-			mprotect(index->mmap_base, index->mmap_used_length,
-				 PROT_READ|PROT_WRITE);
-#endif
-			index->header->flags |= index->set_flags;
-			(void)msync(index->mmap_base, index->header_size,
-				    MS_SYNC);
-		}
-		index->set_flags = 0;
-	}
-
-	index->opened = FALSE;
-	index->inconsistent = FALSE;
-
-	index->lock_type = MAIL_LOCK_UNLOCK;
-	index->header = NULL;
-
-	if (index->fd != -1) {
-		if (close(index->fd) < 0)
-			index_set_syscall_error(index, "close()");
-		index->fd = -1;
-	}
-
-	if (index->filepath != NULL) {
-		i_free(index->filepath);
-		index->filepath = NULL;
-	}
-
-	if (index->anon_mmap) {
-		if (munmap_anon(index->mmap_base, index->mmap_full_length) < 0)
-			index_set_syscall_error(index, "munmap_anon()");
-		index->anon_mmap = FALSE;
-	} else if (index->mmap_base != NULL) {
-		if (munmap(index->mmap_base, index->mmap_full_length) < 0)
-			index_set_syscall_error(index, "munmap()");
-	}
-	index->mmap_base = NULL;
-
-	if (index->cache != NULL) {
-                mail_cache_free(index->cache);
-		index->cache = NULL;
-	}
-
-	if (index->modifylog != NULL) {
-                mail_modifylog_free(index->modifylog);
-		index->modifylog = NULL;
-	}
-
-	if (index->custom_flags != NULL) {
-		mail_custom_flags_free(index->custom_flags);
-                index->custom_flags = NULL;
-	}
-
-	if (index->error != NULL) {
-		i_free(index->error);
-		index->error = NULL;
-	}
-}
-
-static int mail_index_sync_file(struct mail_index *index)
-{
-	unsigned int i;
-	int failed, fsync_fds[3];
-
-	if (index->anon_mmap)
-		return TRUE;
-
-	for (i = 0; i < sizeof(fsync_fds)/sizeof(fsync_fds[0]); i++)
-		fsync_fds[i] = -1;
-
-	if (msync(index->mmap_base, index->mmap_used_length, MS_SYNC) < 0)
-		return index_set_syscall_error(index, "msync()");
-
-	failed = FALSE;
-
-	if (index->modifylog != NULL) {
-		if (!mail_modifylog_sync_file(index->modifylog, &fsync_fds[2]))
-			failed = TRUE;
-	}
-
-	for (i = 0; i < sizeof(fsync_fds)/sizeof(fsync_fds[0]); i++) {
-		if (fsync_fds[i] != -1 && fdatasync(fsync_fds[i]) < 0)
-			index_set_error(index, "fdatasync(%u) failed: %m", i);
-	}
-
-	if (fdatasync(index->fd) < 0)
-		return index_set_syscall_error(index, "fdatasync()");
-
-	return !failed;
-}
-
-int mail_index_fmdatasync(struct mail_index *index, size_t size)
-{
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	if (!index->anon_mmap) {
-		if (msync(index->mmap_base, size, MS_SYNC) < 0)
-			return index_set_syscall_error(index, "msync()");
-		if (fdatasync(index->fd) < 0)
-			return index_set_syscall_error(index, "fdatasync()");
-	}
-
-	return TRUE;
-}
-
-static void mail_index_update_header_changes(struct mail_index *index)
-{
-	if (index->set_flags != 0) {
-		index->header->flags |= index->set_flags;
-		index->set_flags = 0;
-	}
-}
-
-static int mail_index_write_header_changes(struct mail_index *index)
-{
-	int failed = FALSE;
-
-	/* use our own locking here so we don't mess up with any other
-	   index states, like inconsistency. */
-	if (!mail_index_wait_lock(index, F_WRLCK))
-		return FALSE;
-
-#ifdef DEBUG
-	mprotect(index->mmap_base, index->mmap_used_length,
-		 PROT_READ|PROT_WRITE);
-#endif
-
-	mail_index_update_header_changes(index);
-
-	if (!index->anon_mmap) {
-		if (msync(index->mmap_base, index->header_size, MS_SYNC) < 0) {
-			index_set_syscall_error(index, "msync()");
-			failed = TRUE;
-		}
-	}
-
-#ifdef DEBUG
-	mprotect(index->mmap_base, index->mmap_used_length, PROT_NONE);
-#endif
-
-	if (!mail_index_wait_lock(index, F_UNLCK))
-		return FALSE;
-
-	return !failed;
-}
-
-static int mail_index_lock_remove(struct mail_index *index)
-{
-	enum mail_lock_type old_lock_type;
-	int ret = TRUE;
-
-	while (index->cache_later_locks > 0) {
-		if (!mail_cache_unlock(index->cache))
-			ret = FALSE;
-		index->cache_later_locks--;
-	}
-
-	if (!mail_index_wait_lock(index, F_UNLCK))
-		return FALSE;
-
-	old_lock_type = index->lock_type;
-	index->lock_type = MAIL_LOCK_UNLOCK;
-
-	if (old_lock_type == MAIL_LOCK_SHARED) {
-		/* releasing shared lock. we may need to update some
-		   flags in header. */
-		unsigned int old_flags;
-
-		old_flags = index->header->flags;
-
-		if ((old_flags | index->set_flags) != old_flags)
-			return mail_index_write_header_changes(index);
-	}
-
-        debug_mprotect(index->mmap_base, index->mmap_full_length, index);
-	return ret;
-}
-
-static int mail_index_lock_change(struct mail_index *index,
-				  enum mail_lock_type lock_type, int try_lock)
-{
-	int ret, fd_lock_type;
-
-	/* shared -> exclusive can deadlock */
-	i_assert(try_lock || lock_type != MAIL_LOCK_EXCLUSIVE ||
-		 index->lock_type != MAIL_LOCK_SHARED);
-
-	/* locking index when cache is locked can deadlock */
-	i_assert(try_lock || index->lock_type == MAIL_LOCK_EXCLUSIVE ||
-		 index->cache == NULL || !mail_cache_is_locked(index->cache));
-
-	if (index->inconsistent) {
-		/* index is in inconsistent state and nothing else than
-		   free() is allowed for it. */
-		if (index->error == NULL) {
-			index->error =
-				i_strdup("Index is in inconsistent state");
-		}
-		return FALSE;
-	}
-
-	fd_lock_type = MAIL_LOCK_TO_FLOCK(lock_type);
-	if (try_lock) {
-		ret = file_try_lock(index->fd, fd_lock_type);
-		if (ret < 0)
-			index_set_syscall_error(index, "file_try_lock()");
-		if (ret <= 0)
-			return FALSE;
-	} else {
-		if (!mail_index_wait_lock(index, fd_lock_type))
-			return FALSE;
-	}
-
-	index->lock_type = lock_type;
-	debug_mprotect(index->mmap_base, index->mmap_full_length, index);
-
-	if (!mail_index_mmap_update(index)) {
-		(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
-		return FALSE;
-	}
-
-	if (index->indexid != index->header->indexid) {
-		/* index was rebuilt, there's no way we can maintain
-		   consistency */
-		index_set_error(index, "Warning: Inconsistency - Index "
-				"%s was rebuilt while we had it open",
-				index->filepath);
-		index->inconsistent = TRUE;
-		return FALSE;
-	}
-
-	if (index->header->flags & MAIL_INDEX_HDR_FLAG_FSCK) {
-		/* someone just partially updated the index, need to fsck it */
-		if (lock_type == MAIL_LOCK_SHARED) {
-			/* we need exclusive lock so fsck()'s set_lock() won't
-			   get us back here */
-			if (!mail_index_lock_remove(index))
-				return FALSE;
-
-			if (!mail_index_wait_lock(index, F_WRLCK))
-				return FALSE;
-			index->lock_type = MAIL_LOCK_EXCLUSIVE;
-
-			debug_mprotect(index->mmap_base,
-				       index->mmap_full_length, index);
-		}
-
-		/* check again, in case it was already fscked while we had
-		   it unlocked for a while */
-		if (index->header->flags & MAIL_INDEX_HDR_FLAG_FSCK) {
-			if (!index->fsck(index))
-				return FALSE;
-		}
-
-		if (lock_type == MAIL_LOCK_SHARED) {
-			/* drop exclusive lock */
-			return index->set_lock(index, lock_type);
-		}
-	}
-
-	if (lock_type == MAIL_LOCK_EXCLUSIVE) {
-		/* while holding exclusive lock, keep the FSCK flag on.
-		   when the lock is released, the FSCK flag will also be
-		   removed. */
-		index->excl_lock_counter++;
-		index->header->flags |= MAIL_INDEX_HDR_FLAG_FSCK;
-		if (!mail_index_fmdatasync(index, index->header_size)) {
-			(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-static int mail_index_lock_full(struct mail_index *index,
-				enum mail_lock_type lock_type, int try_lock)
-{
-	int keep_fsck;
-
-	if (index->lock_type == lock_type)
-		return TRUE;
-
-	if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
-		index->excl_lock_counter++;
-		if (index->modifylog != NULL)
-			mail_modifylog_notify_lock_drop(index->modifylog);
-	}
-
-	if (index->anon_mmap) {
-		/* anonymous mmaps are private and don't need any locking */
-#ifdef DEBUG
-		mprotect(index->mmap_base, index->mmap_used_length,
-			 PROT_READ|PROT_WRITE);
-#endif
-		mail_index_update_header_changes(index);
-
-		index->lock_type = lock_type;
-		debug_mprotect(index->mmap_base, index->mmap_full_length,
-			       index);
-		return TRUE;
-	}
-
-	if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
-		/* dropping exclusive lock (either unlock or to shared) */
-		keep_fsck = (index->set_flags & MAIL_INDEX_HDR_FLAG_FSCK) != 0;
-		mail_index_update_header_changes(index);
-
-		if (index->sync_dirty_stamp == 0) {
-			index->header->sync_stamp = index->sync_stamp;
-			index->header->sync_size = index->sync_size;
-		}
-
-		/* remove the FSCK flag only after successful fsync() */
-		if (mail_index_sync_file(index) && !keep_fsck) {
-			index->header->flags &= ~MAIL_INDEX_HDR_FLAG_FSCK;
-			if (msync(index->mmap_base, index->header_size,
-				  MS_SYNC) < 0) {
-				/* we only failed to remove the fsck flag,
-				   so this isn't fatal. */
-				index_set_syscall_error(index, "msync()");
-			}
-		}
-	}
-
-	if (lock_type == MAIL_LOCK_UNLOCK)
-		return mail_index_lock_remove(index);
-	else
-		return mail_index_lock_change(index, lock_type, try_lock);
-}
-
-int mail_index_set_lock(struct mail_index *index, enum mail_lock_type lock_type)
-{
-	return mail_index_lock_full(index, lock_type, FALSE);
-}
-
-int mail_index_try_lock(struct mail_index *index, enum mail_lock_type lock_type)
-{
-	return mail_index_lock_full(index, lock_type, TRUE);
-}
-
-void mail_index_set_lock_notify_callback(struct mail_index *index,
-					 mail_lock_notify_callback_t callback,
-					 void *context)
-{
-	index->lock_notify_cb = callback;
-	index->lock_notify_context = context;
-}
-
-struct mail_index_header *mail_index_get_header(struct mail_index *index)
-{
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-
-	return index->header;
-}
-
-void mail_index_mark_flag_changes(struct mail_index *index,
-				  struct mail_index_record *rec,
-				  enum mail_flags old_flags,
-				  enum mail_flags new_flags)
-{
-	if ((old_flags & MAIL_SEEN) == 0 && (new_flags & MAIL_SEEN)) {
-		/* unseen -> seen */
-		index->header->seen_messages_count++;
-		if (index->header->first_unseen_uid_lowwater == rec->uid)
-			index->header->first_unseen_uid_lowwater++;
-	} else if ((old_flags & MAIL_SEEN) && (new_flags & MAIL_SEEN) == 0) {
-		/* seen -> unseen */
-		if (index->header->seen_messages_count ==
-		    index->header->messages_count) {
-			/* this is the first unseen message */
-                        index->header->first_unseen_uid_lowwater = rec->uid;
-		} else if (rec->uid < index->header->first_unseen_uid_lowwater)
-			index->header->first_unseen_uid_lowwater = rec->uid;
-
-		if (index->header->seen_messages_count == 0) {
-			index_set_corrupted(index,
-				"seen_messages_count in header is invalid");
-		} else {
-			index->header->seen_messages_count--;
-		}
-	}
-
-	if ((old_flags & MAIL_DELETED) == 0 && (new_flags & MAIL_DELETED)) {
-		/* undeleted -> deleted */
-		index->header->deleted_messages_count++;
-
-		if (index->header->deleted_messages_count == 1) {
-			/* this is the first deleted message */
-			index->header->first_deleted_uid_lowwater = rec->uid;
-		} else if (rec->uid < index->header->first_deleted_uid_lowwater)
-			index->header->first_deleted_uid_lowwater = rec->uid;
-	} else if ((old_flags & MAIL_DELETED) &&
-		   (new_flags & MAIL_DELETED) == 0) {
-		/* deleted -> undeleted */
-		if (index->header->first_deleted_uid_lowwater == rec->uid)
-			index->header->first_deleted_uid_lowwater++;
-		if (index->header->deleted_messages_count == 0) {
-			index_set_corrupted(index,
-				"deleted_messages_count in header is invalid");
-		} else {
-			index->header->deleted_messages_count--;
-		}
-	}
-}
-
-#define INDEX_NEED_COMPRESS(records, hdr) \
-	((records) > INDEX_MIN_RECORDS_COUNT && \
-	 (records) * (100-INDEX_COMPRESS_PERCENTAGE) / 100 > \
-	 	(hdr)->messages_count)
-
-int mail_index_expunge(struct mail_index *index,
-		       struct mail_index_record *first_rec,
-		       struct mail_index_record *last_rec,
-		       unsigned int first_seq, unsigned int last_seq,
-		       int external_change)
-{
-	unsigned int first_uid, last_uid;
-
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-	i_assert(first_seq != 0);
-	i_assert(first_seq <= last_seq);
-
-	index->expunge_counter++;
-
-	first_uid = first_rec->uid;
-	last_uid = last_rec->uid;
-
-	if (!mail_index_expunge_record_range(index, first_rec, last_rec))
-		return FALSE;
-
-	if (index->modifylog != NULL) {
-		if (!mail_modifylog_add_expunges(index->modifylog,
-						 first_seq, last_seq,
-						 first_uid, last_uid,
-						 external_change))
-			return FALSE;
-	}
-
-	if (index->header->messages_count == 0) {
-		/* all mail was deleted, truncate cache file */
-		if (!mail_cache_truncate(index->cache))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-int mail_index_update_flags(struct mail_index *index,
-			    struct mail_index_record *rec, unsigned int seq,
-			    enum modify_type modify_type, enum mail_flags flags,
-			    int external_change)
-{
-	enum mail_flags new_flags;
-
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-	i_assert(seq != 0);
-
-	switch (modify_type) {
-	case MODIFY_ADD:
-		new_flags = rec->msg_flags | flags;
-		break;
-	case MODIFY_REMOVE:
-		new_flags = rec->msg_flags & ~flags;
-		break;
-	case MODIFY_REPLACE:
-		new_flags = flags;
-		break;
-	default:
-		new_flags = 0;
-		i_unreached();
-	}
-
-	if (new_flags == rec->msg_flags)
-		return TRUE; /* no changes */
-
-        mail_index_mark_flag_changes(index, rec, rec->msg_flags, new_flags);
-
-	rec->msg_flags = new_flags;
-	return index->modifylog == NULL ? TRUE :
-		mail_modifylog_add_flags(index->modifylog, seq,
-					 rec->uid, external_change);
-}
-
-static int mail_index_grow(struct mail_index *index)
-{
-	uoff_t pos;
-	unsigned int grow_count;
-	void *base;
-
-	grow_count = index->header->messages_count *
-		INDEX_GROW_PERCENTAGE / 100;
-	if (grow_count < 16)
-		grow_count = 16;
-
-	pos = index->mmap_full_length +
-		(grow_count * sizeof(struct mail_index_record));
-	i_assert(pos < OFF_T_MAX);
-
-	if (index->anon_mmap) {
-		i_assert(pos < SSIZE_T_MAX);
-
-		base = mremap_anon(index->mmap_base, index->mmap_full_length,
-				   (size_t)pos, MREMAP_MAYMOVE);
-		if (base == MAP_FAILED)
-			return index_set_syscall_error(index, "mremap_anon()");
-
-		index->mmap_base = base;
-		index->mmap_full_length = (size_t)pos;
-		return mmap_verify(index);
-	}
-
-	if (file_set_size(index->fd, (off_t)pos) < 0)
-		return index_set_syscall_error(index, "file_set_size()");
-
-	/* file size changed, let others know about it too by changing
-	   sync_id in header. */
-	index->header->master_sync_id++;
-
-	if (!mail_index_mmap_update(index))
-		return FALSE;
-
-	return TRUE;
-}
-
-struct mail_index_record *mail_index_append(struct mail_index *index)
-{
-	struct mail_index_record *rec;
-
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	if (index->header->next_uid == MAX_ALLOWED_UID) {
-		index->set_flags |= MAIL_INDEX_HDR_FLAG_REBUILD;
-		index_set_error(index, "Reached maximum UID in mailbox %s, "
-				"rebuilding index", index->filepath);
-		return NULL;
-	}
-
-	if (index->mmap_used_length == index->mmap_full_length) {
-		if (!mail_index_grow(index))
-			return NULL;
-	}
-
-	i_assert(index->header->used_file_size == index->mmap_used_length);
-	i_assert(index->mmap_used_length + sizeof(struct mail_index_record) <=
-		 index->mmap_full_length);
-
-	index->header->messages_count++;
-
-	rec = (struct mail_index_record *) ((char *) index->mmap_base +
-					    index->mmap_used_length);
-	rec->uid = index->header->next_uid++;
-	rec->msg_flags = 0;
-	rec->cache_offset = 0;
-
-	index->header->used_file_size += sizeof(*rec);
-	index->mmap_used_length += sizeof(*rec);
-
-	return rec;
-}
-
-enum mail_index_error mail_index_get_last_error(struct mail_index *index)
-{
-	if (index->inconsistent)
-		return MAIL_INDEX_ERROR_INCONSISTENT;
-	if (index->nodiskspace)
-		return MAIL_INDEX_ERROR_DISKSPACE;
-	if (index->index_lock_timeout)
-		return MAIL_INDEX_ERROR_INDEX_LOCK_TIMEOUT;
-	if (index->mailbox_lock_timeout)
-		return MAIL_INDEX_ERROR_MAILBOX_LOCK_TIMEOUT;
-
-	if (index->error != NULL)
-		return MAIL_INDEX_ERROR_INTERNAL;
-
-	return MAIL_INDEX_ERROR_NONE;
-}
-
-const char *mail_index_get_last_error_text(struct mail_index *index)
-{
-	return index->error;
-}
--- a/src/lib-index/mail-index.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,496 +0,0 @@
-#ifndef __MAIL_INDEX_H
-#define __MAIL_INDEX_H
-
-#include "file-dotlock.h"
-#include "message-parser.h"
-#include "imap-util.h"
-
-#define MAIL_INDEX_MAJOR_VERSION 3
-#define MAIL_INDEX_MINOR_VERSION 0
-
-#define INDEX_FILE_PREFIX ".imap.index"
-
-enum mail_index_open_flags {
-	/* Create index if it doesn't exist */
-	MAIL_INDEX_OPEN_FLAG_CREATE		= 0x01,
-	/* Update \Recent flag counters */
-	MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT	= 0x02,
-	/* Compressing and cache updates are not performed */
-	MAIL_INDEX_OPEN_FLAG_FAST		= 0x04,
-	/* Invalidate memory maps before accessing them */
-	MAIL_INDEX_OPEN_FLAG_MMAP_INVALIDATE	= 0x08,
-
-	/* internal: we're creating the index */
-	_MAIL_INDEX_OPEN_FLAG_CREATING		= 0x100
-};
-
-enum mail_index_header_compat_flags {
-	MAIL_INDEX_COMPAT_LITTLE_ENDIAN		= 0x01
-};
-
-enum mail_index_header_flag {
-	/* Rebuild flag is set while index is being rebuilt or when
-	   some error is noticed in the index file. If this flag is set,
-	   the index shouldn't be used before rebuilding it. */
-	MAIL_INDEX_HDR_FLAG_FSCK		= 0x0001,
-	MAIL_INDEX_HDR_FLAG_REBUILD		= 0x0002,
-	MAIL_INDEX_HDR_FLAG_COMPRESS		= 0x0004,
-	MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE	= 0x0008,
-	MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES	= 0x0010,
-	MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS	= 0x0020,
-	MAIL_INDEX_HDR_FLAG_MAILDIR_NEW		= 0x0040
-};
-
-enum mail_index_record_flag {
-	/* If binary flags are set, it's not checked whether mail is
-	   missing CRs. So this flag may be set as an optimization for
-	   regular non-binary mails as well if it's known that it contains
-	   valid CR+LF line breaks. */
-	MAIL_INDEX_FLAG_BINARY_HEADER		= 0x0001,
-	MAIL_INDEX_FLAG_BINARY_BODY		= 0x0002,
-
-	/* Mail flags have been changed in index, but not written into
-	   actual mailbox yet. */
-	MAIL_INDEX_FLAG_DIRTY			= 0x0004,
-
-	/* Maildir: Mail file is in new/ dir instead of cur/ */
-	MAIL_INDEX_FLAG_MAILDIR_NEW		= 0x0008,
-
-	/* Mail header or body is known to contain NUL characters. */
-	MAIL_INDEX_FLAG_HAS_NULS		= 0x0010,
-	/* Mail header or body is known to not contain NUL characters. */
-	MAIL_INDEX_FLAG_HAS_NO_NULS		= 0x0020
-};
-
-enum mail_lock_type {
-	MAIL_LOCK_UNLOCK = 0,
-	MAIL_LOCK_SHARED,
-	MAIL_LOCK_EXCLUSIVE
-};
-
-enum mail_lock_notify_type {
-	/* Mailbox is locked, will abort in secs_left */
-	MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
-	/* Mailbox lock looks stale, will override in secs_left */
-	MAIL_LOCK_NOTIFY_MAILBOX_OVERRIDE,
-	/* Index is locked, will abort in secs_left */
-	MAIL_LOCK_NOTIFY_INDEX_ABORT
-};
-
-enum mail_index_error {
-	/* No errors */
-	MAIL_INDEX_ERROR_NONE,
-	/* Internal error, see get_error_text() for more information. */
-	MAIL_INDEX_ERROR_INTERNAL,
-	/* Index is now in inconsistent state with the previous known state,
-	   meaning that the message IDs etc. may have changed - only way to
-	   recover this would be to fully close the mailbox and reopen it.
-	   With IMAP this would mean a forced disconnection since we can't do
-	   forced CLOSE. */
-	MAIL_INDEX_ERROR_INCONSISTENT,
-	/* We ran out of available disk space. */
-	MAIL_INDEX_ERROR_DISKSPACE,
-	/* Mail index locking timeouted */
-	MAIL_INDEX_ERROR_INDEX_LOCK_TIMEOUT,
-	/* Mailbox locking timeouted */
-	MAIL_INDEX_ERROR_MAILBOX_LOCK_TIMEOUT
-};
-
-typedef void mail_lock_notify_callback_t(enum mail_lock_notify_type notify_type,
-					 unsigned int secs_left, void *context);
-
-struct mail_index_header {
-	/* major version is increased only when you can't have backwards
-	   compatibility. minor version is increased when header size is
-	   increased to contain new non-critical fields. */
-	uint8_t major_version;
-	uint8_t minor_version;
-	uint8_t header_size;
-	uint8_t reserved;
-
-	/* 0 = flags
-	   1 = sizeof(uoff_t)
-	   2 = sizeof(time_t)
-	   3 = reserved, 0 for now */
-	uint8_t compat_data[4];
-
-	uint32_t indexid;
-	uint32_t used_file_size;
-
-	/* file needs to be reopened if sync_ids change. */
-	uint32_t master_sync_id;
-	uint32_t cache_sync_id;
-	uint32_t log_sync_id;
-
-	uint32_t flags;
-
-	uint32_t uid_validity;
-	uint32_t next_uid;
-
-	uint32_t messages_count;
-	uint32_t seen_messages_count;
-	uint32_t deleted_messages_count;
-	uint32_t last_nonrecent_uid;
-
-	/* these UIDs may not exist and may not even be unseen */
-	uint32_t first_unseen_uid_lowwater;
-	uint32_t first_deleted_uid_lowwater;
-
-	uint64_t sync_size;
-	uint32_t sync_stamp;
-};
-
-struct mail_index_record {
-	uint32_t uid;
-	uint32_t msg_flags;
-	uint32_t cache_offset;
-};
-
-struct mail_index {
-	/* Note that opening same index twice in the same process is a bad
-	   idea since they share the same file locks. As soon one of the
-	   indexes is closed, the locks in second index are dropped which
-	   especially hurts modify log since it keeps locks all the time. */
-	int (*open)(struct mail_index *index, enum mail_index_open_flags flags);
-
-	/* Free index from memory. */
-	void (*free)(struct mail_index *index);
-
-	/* Lock/unlock index. May block. Note that unlocking must not
-	   reset error from get_last_error() as unlocking can be done as
-	   a cleanup after some other function failed. Index is always
-	   mmap()ed after set_lock() succeeds.
-
-	   Trying to change a shared lock into exclusive lock is a fatal
-	   error, since it may create a deadlock. Even though operating
-	   system should detect it and fail, it's not a good idea to even
-	   let it happen. Better ways to do this would be to a) mark the
-	   data to be updated later, b) use try_lock() if the update is
-	   preferred but not required, c) unlock + lock again, but make
-	   sure that won't create race conditions. */
-	int (*set_lock)(struct mail_index *index,
-			enum mail_lock_type lock_type);
-
-	/* Try locking the index. Returns TRUE if the lock was got and
-	   FALSE if lock isn't possible to get currently or some other error
-	   occured. Never blocks. */
-	int (*try_lock)(struct mail_index *index,
-			enum mail_lock_type lock_type);
-
-	/* If we have to wait for the lock, the given lock notify function
-	   is called once in a while. */
-	void (*set_lock_notify_callback)(struct mail_index *index,
-					 mail_lock_notify_callback_t *callback,
-					 void *context);
-
-	/* Rebuild the whole index. Note that this changes the indexid
-	   so all the other files must also be rebuilt after this call.
-	   Index MUST NOT have shared lock, but exclusive lock or no lock at
-	   all is fine. Note that this function may leave the index
-	   exclusively locked, and always sets index->inconsistent = TRUE. */
-	int (*rebuild)(struct mail_index *index);
-
-	/* Verify that the index is valid. If anything invalid is found,
-	   index is set inconsistent and to be rebuilt at next open.
-	   Same locking issues as with rebuild(). */
-	int (*fsck)(struct mail_index *index);
-
-	/* Synchronize the index with the mailbox. Index must not have shared
-	   lock when calling this function. The data_lock_type specifies what
-	   lock should be set to data file (mbox file). This function may
-	   leave the index in ANY locking state. If changes is non-NULL, it's
-	   set to TRUE if any changes were noticed. If minimal_sync is TRUE,
-	   we do as little as possible to get data file locked (ie. noop with
-	   maildir). */
-	int (*sync_and_lock)(struct mail_index *index, int minimal_sync,
-			     enum mail_lock_type data_lock_type, int *changes);
-
-	/* Returns the index header (never fails). The index needs to be
-	   locked before calling this function, and must be kept locked as
-	   long as you keep using the returned structure. */
-	struct mail_index_header *(*get_header)(struct mail_index *index);
-
-	/* sequence -> data lookup. The index needs to be locked before calling
-	   this function, and must be kept locked as long as you keep using
-	   the returned structure. */
-	struct mail_index_record *(*lookup)(struct mail_index *index,
-					    unsigned int seq);
-
-	/* Return the next record after specified record, or NULL if it was
-	   last record. The index must be locked all the time between
-	   lookup() and last next() call. rec must not have been expunged. */
-	struct mail_index_record *(*next)(struct mail_index *index,
-					  struct mail_index_record *rec);
-
-	/* Find first existing UID in range. Sequence number is also retrieved
-	   if seq_r is non-NULL. */
-	struct mail_index_record *(*lookup_uid_range)(struct mail_index *index,
-						      unsigned int first_uid,
-						      unsigned int last_uid,
-						      unsigned int *seq_r);
-
-	/* Open mail file and return it as mmap()ed IStream. If we fail,
-	   we return NULL and set deleted = TRUE if failure was because the
-	   mail was just deleted (ie. not an error). received_date is set
-	   if it's non-NULL. */
-	struct istream *(*open_mail)(struct mail_index *index,
-				     struct mail_index_record *rec,
-				     time_t *received_date, int *deleted);
-
-	/* Returns received date of message, or (time_t)-1 if error occured. */
-	time_t (*get_received_date)(struct mail_index *index,
-				    struct mail_index_record *rec);
-
-	/* Expunge mails from index. Modifylog is also updated. The
-	   index must be exclusively locked before calling this function.
-
-	   first_rec+1 .. last_rec-1 range may contain already expunged
-	   records.
-
-	   Note that all record pointers are invalidated after this call as
-	   expunging may radically modify the file. */
-	int (*expunge)(struct mail_index *index,
-		       struct mail_index_record *first_rec,
-		       struct mail_index_record *last_rec,
-		       unsigned int first_seq, unsigned int last_seq,
-		       int external_change);
-
-	/* Update mail flags. The index must be exclusively locked before
-	   calling this function. */
-	int (*update_flags)(struct mail_index *index,
-			    struct mail_index_record *rec, unsigned int seq,
-			    enum modify_type modify_type, enum mail_flags flags,
-			    int external_change);
-
-	/* Append a new record to index. The index must be exclusively
-	   locked before calling this function. */
-	struct mail_index_record *(*append)(struct mail_index *index);
-
-	/* Returns the last error code. */
-	enum mail_index_error (*get_last_error)(struct mail_index *index);
-
-	/* Returns the full error message for last error. This message may
-	   contain paths etc. so it shouldn't be shown to users. */
-	const char *(*get_last_error_text)(struct mail_index *index);
-
-/* private: */
-	struct mail_cache *cache;
-	struct mail_modify_log *modifylog;
-	struct mail_custom_flags *custom_flags;
-
-	char *dir; /* directory where to place the index files */
-	char *filepath; /* index file path */
-	char *mailbox_path; /* file/directory for mailbox location */
-	char *control_dir; /* destination for control files */
-	unsigned int indexid;
-	unsigned int master_sync_id, cache_sync_id, log_sync_id;
-
-        /* updated whenever exclusive lock is set/unset */
-	unsigned int excl_lock_counter;
-	/* updated whenever expunge() is called */
-	unsigned int expunge_counter;
-
-	int mbox_fd;
-	struct istream *mbox_stream;
-	enum mail_lock_type mbox_lock_type;
-	struct dotlock mbox_dotlock;
-
-	/* these counters can be used to check that we've synced the mailbox
-	   after locking it */
-	unsigned int mbox_lock_counter;
-	unsigned int mbox_sync_counter;
-
-	/* last mbox sync: */
-	dev_t mbox_dev;
-	ino_t mbox_ino;
-
-	/* last maildir sync: */
-	time_t last_new_mtime, last_uidlist_mtime;
-	int maildir_lock_fd;
-	pool_t new_filename_pool;
-	struct hash_table *new_filenames;
-
-	int fd; /* opened index file */
-	char *error; /* last error message */
-
-	void *mmap_base;
-	size_t mmap_used_length;
-	size_t mmap_full_length;
-
-	struct mail_index_header *header;
-	size_t header_size;
-
-        enum mail_lock_type lock_type;
-	time_t sync_stamp, sync_dirty_stamp;
-	uoff_t sync_size;
-	time_t next_dirty_flags_flush;
-	unsigned int first_recent_uid;
-
-	mail_lock_notify_callback_t *lock_notify_cb;
-	void *lock_notify_context;
-
-        mode_t mail_create_mode;
-	unsigned int private_flags_mask;
-
-	/* these fields are OR'ed to the fields in index header once we
-	   get around grabbing exclusive lock */
-	unsigned int set_flags;
-	unsigned int cache_later_locks;
-
-	unsigned int anon_mmap:1;
-	unsigned int mmap_invalidate:1;
-	unsigned int mbox_rewritten:1;
-	unsigned int opened:1;
-	unsigned int rebuilding:1;
-	unsigned int mail_read_mmaped:1;
-	unsigned int inconsistent:1;
-	unsigned int nodiskspace:1;
-	unsigned int index_lock_timeout:1;
-	unsigned int allow_new_custom_flags:1;
-	unsigned int mailbox_readonly:1;
-	unsigned int mailbox_lock_timeout:1;
-	unsigned int maildir_keep_new:1;
-	unsigned int maildir_have_new:1;
-	unsigned int maildir_synced_once:1;
-};
-
-#ifdef DEV_T_STRUCT
-/* we can't initialize dev_t as 0, and we don't know what it actually
-   contains, so don't initialize them. gcc's -W option should be disabled
-   with this or we get warnings.. */
-#  define MAIL_INDEX_PRIVATE_FILL 0
-#else
-/* needed to remove annoying warnings about not initializing all struct
-   members.. */
-#define MAIL_INDEX_PRIVATE_FILL \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, { 0, 0, 0 }, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0
-#endif
-
-/* defaults - same as above but prefixed with mail_index_. */
-int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags);
-int mail_index_set_lock(struct mail_index *index,
-			enum mail_lock_type lock_type);
-int mail_index_try_lock(struct mail_index *index,
-			enum mail_lock_type lock_type);
-void mail_index_set_lock_notify_callback(struct mail_index *index,
-					 mail_lock_notify_callback_t *callback,
-					 void *context);
-int mail_index_fsck(struct mail_index *index);
-struct mail_index_header *mail_index_get_header(struct mail_index *index);
-struct mail_index_record *mail_index_lookup(struct mail_index *index,
-					    unsigned int seq);
-struct mail_index_record *mail_index_next(struct mail_index *index,
-					  struct mail_index_record *rec);
-struct mail_index_record *
-mail_index_lookup_uid_range(struct mail_index *index, unsigned int first_uid,
-			    unsigned int last_uid, unsigned int *seq_r);
-int mail_index_expunge(struct mail_index *index,
-		       struct mail_index_record *first_rec,
-		       struct mail_index_record *last_rec,
-		       unsigned int first_seq, unsigned int last_seq,
-		       int external_change);
-int mail_index_update_flags(struct mail_index *index,
-			    struct mail_index_record *rec, unsigned int seq,
-			    enum modify_type modify_type, enum mail_flags flags,
-			    int external_change);
-struct mail_index_record *mail_index_append(struct mail_index *index);
-enum mail_index_error mail_index_get_last_error(struct mail_index *index);
-const char *mail_index_get_last_error_text(struct mail_index *index);
-
-/* INTERNAL: */
-void mail_index_init(struct mail_index *index, const char *dir);
-int mail_index_mmap_update(struct mail_index *index);
-void mail_index_init_header(struct mail_index_header *hdr);
-void mail_index_close(struct mail_index *index);
-int mail_index_fmdatasync(struct mail_index *index, size_t size);
-void mail_index_mark_flag_changes(struct mail_index *index,
-				  struct mail_index_record *rec,
-				  enum mail_flags old_flags,
-				  enum mail_flags new_flags);
-int mail_index_rebuild(struct mail_index *index);
-int mail_index_compress(struct mail_index *index);
-int mail_index_truncate(struct mail_index *index);
-int mail_index_expunge_record_range(struct mail_index *index,
-				    struct mail_index_record *first_rec,
-				    struct mail_index_record *last_rec);
-
-/* Maximum allowed UID number. */
-#define MAX_ALLOWED_UID 4294967295U /* 2^32 - 1 */
-
-/* Max. mmap()ed size for a message */
-#define MAIL_MMAP_BLOCK_SIZE (1024*256)
-/* Block size when read()ing message. */
-#define MAIL_READ_BLOCK_SIZE (1024*8)
-
-/* Delete unused non-local temp files after 24h. Just to be sure we don't
-   delete it too early. The temp files don't harm much anyway. */
-#define TEMP_FILE_TIMEOUT (60*24)
-
-/* number of records to always keep allocated in index file,
-   either used or unused */
-#define INDEX_MIN_RECORDS_COUNT 64
-/* when empty space in index file gets full, grow the file n% larger */
-#define INDEX_GROW_PERCENTAGE 10
-/* ftruncate() the index file when only n% of it is in use */
-#define INDEX_TRUNCATE_PERCENTAGE 30
-/* don't truncate whole file anyway, keep n% of the empty space */
-#define INDEX_TRUNCATE_KEEP_PERCENTAGE 10
-/* Compress the file when deleted space reaches n% of total size */
-#define INDEX_COMPRESS_PERCENTAGE 50
-/* Compress the file when searching deleted records tree has to go this deep */
-#define INDEX_COMPRESS_DEPTH 10
-
-/* uoff_t to index file for given record */
-#define INDEX_FILE_POSITION(index, ptr) \
-	((uoff_t) ((char *) (ptr) - (char *) ((index)->mmap_base)))
-
-/* record for given index */
-#define INDEX_RECORD_AT(index, idx) \
-	((struct mail_index_record *) \
-	 ((char *) index->mmap_base + (index)->header_size) + (idx))
-
-/* returns the next record after last one */
-#define INDEX_END_RECORD(index) \
-	((struct mail_index_record *) \
-	 ((char *) (index)->mmap_base + (index)->mmap_used_length))
-
-/* index number for uoff_t position */
-#define INDEX_POSITION_INDEX(index, pos) \
-	(((pos) - (index)->header_size) / \
-	 sizeof(struct mail_index_record))
-
-/* index number for given record */
-#define INDEX_RECORD_INDEX(index, ptr) \
-	INDEX_POSITION_INDEX(index, INDEX_FILE_POSITION(index, ptr))
-
-/* mark the index corrupted */
-#define INDEX_MARK_CORRUPTED(index) \
-	STMT_START { \
-		(index)->set_flags |= MAIL_INDEX_HDR_FLAG_REBUILD; \
-	} STMT_END
-
-/* get number of records in mmaped index */
-#define MAIL_INDEX_RECORD_COUNT(index) \
-	((index->mmap_used_length - (index)->header_size) / \
-	 sizeof(struct mail_index_record))
-
-/* minimum size for index file */
-#define INDEX_FILE_MIN_SIZE(index) \
-	((index)->header_size + \
-	 INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record))
-
-/* enum mail_lock_type to fcntl() lock type */
-#define MAIL_LOCK_TO_FLOCK(lock_type) \
-        ((lock_type) == MAIL_LOCK_EXCLUSIVE ? F_WRLCK : \
-		(lock_type) == MAIL_LOCK_SHARED ? F_RDLCK : F_UNLCK)
-
-#define INDEX_IS_IN_MEMORY(index) \
-	((index)->anon_mmap)
-
-#endif
--- a/src/lib-index/mail-modifylog.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1298 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "buffer.h"
-#include "file-lock.h"
-#include "file-set-size.h"
-#include "mmap-util.h"
-#include "write-full.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-modifylog.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-/* Maximum size for modify log (isn't exact) */
-#define MAX_MODIFYLOG_SIZE (4096*8)
-
-/* How large chunks to use to grow log file */
-#define MODIFYLOG_GROW_SIZE (sizeof(struct modify_log_record) * 128)
-
-#define MODIFY_LOG_INITIAL_SIZE \
-	(sizeof(struct modify_log_header) + MODIFYLOG_GROW_SIZE)
-
-#define MODIFYLOG_FILE_POSITION(log, ptr) \
-	((size_t) ((char *) (ptr) - (char *) (log)->mmap_base))
-
-/* FIXME: not ANSI-C */
-#define IS_PTR_IN_RANGE(ptr, area_ptr, area_size) \
-	((char *) (ptr) >= (char *) (area_ptr) && \
-	 (char *) (ptr) < (char *) (area_ptr) + (area_size))
-
-struct modify_log_file {
-	struct mail_modify_log *log;
-
-	int fd;
-	char *filepath;
-
-	void *mmap_base;
-	size_t mmap_used_length;
-	size_t mmap_full_length;
-
-	struct modify_log_record *last_expunge, *last_flags;
-	int last_expunge_external, last_flags_external;
-
-	struct modify_log_header *header;
-	uoff_t synced_position;
-	unsigned int synced_id;
-
-	unsigned int anon_mmap:1;
-	unsigned int modified:1;
-	unsigned int second_log:1;
-};
-
-struct mail_modify_log {
-	struct mail_index *index;
-
-	struct modify_log_record *iterator_end;
-
-	struct modify_log_file file1, file2;
-	struct modify_log_file *head, *tail;
-
-	int cache_have_others;
-	unsigned int cache_lock_counter;
-};
-
-static const struct modify_log_expunge no_expunges = { 0, 0, 0 };
-
-static int modifylog_set_syscall_error(struct modify_log_file *file,
-				       const char *function)
-{
-	i_assert(function != NULL);
-
-	if (ENOSPACE(errno)) {
-		file->log->index->nodiskspace = TRUE;
-		return FALSE;
-	}
-
-	index_set_error(file->log->index,
-			"%s failed with modify log file %s: %m",
-			function, file->filepath);
-	return FALSE;
-}
-
-static int modifylog_set_corrupted(struct modify_log_file *file,
-				   const char *fmt, ...)
-{
-	va_list va;
-
-	va_start(va, fmt);
-	t_push();
-
-	index_set_error(file->log->index, "Corrupted modify log file %s: %s",
-			file->filepath, t_strdup_vprintf(fmt, va));
-
-	t_pop();
-	va_end(va);
-
-	/* make sure we don't get back here */
-	file->log->index->inconsistent = TRUE;
-	(void)unlink(file->filepath);
-
-	return FALSE;
-}
-
-static int modifylog_drop_lock(struct modify_log_file *file)
-{
-	int ret;
-
-	/* revert back to shared lock */
-	ret = file_try_lock(file->fd, F_RDLCK);
-	if (ret < 0) {
-		modifylog_set_syscall_error(file, "file_try_lock()");
-		return -1;
-	}
-
-	if (ret == 0) {
-		/* shouldn't happen */
-		index_set_error(file->log->index,
-				"file_try_lock(F_WRLCK -> F_RDLCK) "
-				"failed with file %s", file->filepath);
-		return -1;
-	}
-
-	return 1;
-}
-
-static int modifylog_file_have_other_users(struct modify_log_file *file,
-					   int keep_lock)
-{
-	int ret;
-
-	if (file->anon_mmap)
-		return 0;
-
-	/* try grabbing exclusive lock */
-	ret = file_try_lock(file->fd, F_WRLCK);
-	if (ret <= 0) {
-		if (ret < 0)
-			modifylog_set_syscall_error(file, "file_try_lock()");
-		return ret < 0 ? -1 : 1;
-	}
-
-	if (keep_lock)
-		return 0;
-	else
-		return modifylog_drop_lock(file) < 0 ? -1 : 0;
-}
-
-/* returns 1 = yes, 0 = no, -1 = error */
-static int modifylog_have_other_users(struct mail_modify_log *log,
-				      int keep_lock)
-{
-	struct modify_log_file *file;
-	int ret;
-
-	ret = modifylog_file_have_other_users(log->head, keep_lock);
-	if (ret == 0) {
-		/* check the other file too */
-		file = log->head == &log->file1 ? &log->file2 : &log->file1;
-
-		ret = file->fd == -1 ? 0 :
-			modifylog_file_have_other_users(file, FALSE);
-		if (keep_lock && ret != 0) {
-			if (modifylog_drop_lock(log->head) < 0)
-				return -1;
-		}
-	}
-
-	return ret;
-}
-
-static int mmap_update(struct modify_log_file *file, int forced)
-{
-	struct modify_log_header *hdr;
-	unsigned int extra;
-
-	if (file->log->index->mmap_invalidate && file->mmap_base != NULL) {
-		if (msync(file->mmap_base, file->mmap_used_length,
-			  MS_SYNC | MS_INVALIDATE) < 0)
-			return modifylog_set_syscall_error(file, "msync()");
-	}
-
-	if (!forced && file->header != NULL &&
-	    file->mmap_full_length >= file->header->used_file_size) {
-		file->mmap_used_length = file->header->used_file_size;
-		debug_mprotect(file->mmap_base, file->mmap_full_length,
-			       file->log->index);
-		return TRUE;
-	}
-
-	i_assert(!file->anon_mmap);
-
-	if (file->mmap_base != NULL) {
-		/* make sure we're synced before munmap() */
-		if (file->modified &&
-		    msync(file->mmap_base, file->mmap_used_length, MS_SYNC) < 0)
-			return modifylog_set_syscall_error(file, "msync()");
-		file->modified = FALSE;
-
-		if (munmap(file->mmap_base, file->mmap_full_length) < 0)
-			modifylog_set_syscall_error(file, "munmap()");
-	}
-
-	file->log->iterator_end = NULL;
-
-	file->mmap_used_length = 0;
-	file->header = NULL;
-
-	file->last_expunge = NULL;
-	file->last_flags = NULL;
-
-	file->mmap_base = mmap_rw_file(file->fd, &file->mmap_full_length);
-	if (file->mmap_base == MAP_FAILED) {
-		file->mmap_base = NULL;
-		return modifylog_set_syscall_error(file, "mmap()");
-	}
-
-	if (file->mmap_full_length < sizeof(struct modify_log_header)) {
-		index_set_error(file->log->index, "Too small modify log %s",
-				file->filepath);
-		(void)unlink(file->filepath);
-		return FALSE;
-	}
-
-	extra = (file->mmap_full_length - sizeof(struct modify_log_header)) %
-		sizeof(struct modify_log_record);
-
-	if (extra != 0) {
-		/* partial write or corrupted -
-		   truncate the file to valid length */
-		file->mmap_full_length -= extra;
-		if (ftruncate(file->fd, (off_t)file->mmap_full_length) < 0)
-			modifylog_set_syscall_error(file, "ftruncate()");
-	}
-
-	hdr = file->mmap_base;
-	if (hdr->used_file_size > file->mmap_full_length) {
-		modifylog_set_corrupted(file,
-			"used_file_size larger than real file size "
-			"(%"PRIuUOFF_T" vs %"PRIuSIZE_T")",
-			hdr->used_file_size, file->mmap_full_length);
-		return FALSE;
-	}
-
-	if (hdr->used_file_size < sizeof(struct modify_log_header) ||
-	    (hdr->used_file_size - sizeof(struct modify_log_header)) %
-	    sizeof(struct modify_log_record) != 0) {
-		modifylog_set_corrupted(file,
-			"Invalid used_file_size in header (%"PRIuUOFF_T")",
-			hdr->used_file_size);
-		return FALSE;
-	}
-
-	file->header = file->mmap_base;
-	file->mmap_used_length = hdr->used_file_size;
-	debug_mprotect(file->mmap_base, file->mmap_full_length,
-		       file->log->index);
-	return TRUE;
-}
-
-static int mmap_init_update(struct modify_log_file *file)
-{
-	if (!mmap_update(file, TRUE))
-		return FALSE;
-
-	file->synced_id = file->header->sync_id;
-	file->synced_position = file->mmap_used_length;
-	return TRUE;
-}
-
-static struct mail_modify_log *mail_modifylog_new(struct mail_index *index)
-{
-	struct mail_modify_log *log;
-
-	log = i_new(struct mail_modify_log, 1);
-	log->index = index;
-
-	log->file1.fd = -1;
-	log->file2.fd = -1;
-
-	log->file1.log = log;
-	log->file2.log = log;
-
-	log->file1.filepath = i_strconcat(index->filepath, ".log", NULL);
-	log->file2.filepath = i_strconcat(index->filepath, ".log.2", NULL);
-
-	index->modifylog = log;
-	return log;
-}
-
-static void modifylog_munmap(struct modify_log_file *file)
-{
-	if (file->anon_mmap) {
-		if (munmap_anon(file->mmap_base, file->mmap_full_length) < 0)
-			modifylog_set_syscall_error(file, "munmap_anon()");
-	} else if (file->mmap_base != NULL) {
-		if (munmap(file->mmap_base, file->mmap_full_length) < 0)
-			modifylog_set_syscall_error(file, "munmap()");
-	}
-	file->mmap_base = NULL;
-	file->mmap_full_length = 0;
-	file->mmap_used_length = 0;
-	file->header = NULL;
-
-	file->last_expunge = NULL;
-	file->last_flags = NULL;
-}
-
-static void modifylog_close_file(struct modify_log_file *file)
-{
-	modifylog_munmap(file);
-
-	if (file->fd != -1) {
-		if (close(file->fd) < 0)
-			modifylog_set_syscall_error(file, "close()");
-		file->fd = -1;
-	}
-}
-
-static void mail_modifylog_init_header(struct mail_modify_log *log,
-				       struct modify_log_header *hdr)
-{
-	memset(hdr, 0, sizeof(struct modify_log_header));
-	hdr->indexid = log->index->indexid;
-	hdr->used_file_size = sizeof(struct modify_log_header);
-}
-
-static int mail_modifylog_init_fd(struct modify_log_file *file, int fd)
-{
-        struct modify_log_header hdr;
-
-        mail_modifylog_init_header(file->log, &hdr);
-
-	if (write_full(fd, &hdr, sizeof(hdr)) < 0)
-		return modifylog_set_syscall_error(file, "write_full()");
-
-	if (file_set_size(fd, MODIFY_LOG_INITIAL_SIZE) < 0)
-		return modifylog_set_syscall_error(file, "file_set_size()");
-
-	return TRUE;
-}
-
-static int modifylog_mark_full(struct modify_log_file *file)
-{
-	unsigned int sync_id = SYNC_ID_FULL;
-
-	if (file->mmap_base != NULL) {
-		file->header->sync_id = SYNC_ID_FULL;
-
-		if (msync(file->mmap_base, sizeof(struct modify_log_header),
-			  MS_SYNC) < 0)
-			return modifylog_set_syscall_error(file, "msync()");
-	} else {
-		off_t offset = offsetof(struct modify_log_header, sync_id);
-
-		if (lseek(file->fd, offset, SEEK_SET) < 0)
-			return modifylog_set_syscall_error(file, "lseek()");
-
-		if (write_full(file->fd, &sync_id, sizeof(sync_id)) < 0) {
-			modifylog_set_syscall_error(file, "write_full()");
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-/* Returns 1 = ok, 0 = can't lock file, -1 = error */
-static int modifylog_reuse_or_create_file(struct modify_log_file *file)
-{
-	struct mail_index *index = file->log->index;
-	int fd, ret;
-
-	if (INDEX_IS_IN_MEMORY(index))
-		return -1;
-
-	fd = open(file->filepath, O_RDWR | O_CREAT, 0660);
-	if (fd == -1) {
-		modifylog_set_syscall_error(file, "open()");
-		return -1;
-	}
-
-	/* 1) there's race condition between open() and file_try_lock(), so
-	      if we can't get a lock it means the other process did
-	   2) this function is also called by try_switch_log() which uses
-	      this check to make sure it's not locked by others. */
-	ret = file_try_lock(fd, F_WRLCK);
-	if (ret < 0)
-		modifylog_set_syscall_error(file, "file_try_lock()");
-
-	if (ret > 0 && mail_modifylog_init_fd(file, fd)) {
-		/* drop back to read lock */
-		if (file_try_lock(fd, F_RDLCK) <= 0) {
-			modifylog_set_syscall_error(file, "file_try_lock()");
-			ret = -1;
-		}
-
-		if (ret > 0) {
-			file->fd = fd;
-			return 1;
-		}
-	}
-
-	if (close(fd) < 0)
-		modifylog_set_syscall_error(file, "close()");
-	return ret;
-}
-
-/* Returns 1 = ok, 0 = full, -1 = error */
-static int mail_modifylog_open_and_verify(struct modify_log_file *file)
-{
-	struct mail_index *index = file->log->index;
-	struct modify_log_header hdr;
-	ssize_t ret;
-	int fd;
-
-	fd = open(file->filepath, O_RDWR);
-	if (fd == -1) {
-		if (errno != ENOENT)
-			modifylog_set_syscall_error(file, "open()");
-		return -1;
-	}
-
-	if (file_wait_lock(fd, F_RDLCK) <= 0) {
-		modifylog_set_syscall_error(file, "file_wait_lock()");
-		(void)close(fd);
-		return -1;
-	}
-
-	ret = read(fd, &hdr, sizeof(hdr));
-	if (ret < 0)
-		modifylog_set_syscall_error(file, "read()");
-	else if (ret != sizeof(hdr)) {
-		index_set_error(index, "Corrupted modify log %s: "
-				"File too small", file->filepath);
-		ret = -1;
-
-		(void)unlink(file->filepath);
-	} else {
-		ret = 1;
-	}
-
-	if (ret > 0 && hdr.indexid != index->indexid) {
-		index_set_error(index, "IndexID mismatch for modify log file "
-				"%s", file->filepath);
-		ret = -1;
-
-		/* we have to rebuild it, make sure it's deleted. */
-		(void)unlink(file->filepath);
-	}
-
-	if (ret > 0 && hdr.sync_id == SYNC_ID_FULL) {
-		/* full */
-		ret = 0;
-	}
-
-	if (ret > 0)
-		file->fd = fd;
-	else
-		(void)close(fd);
-
-	return ret;
-}
-
-static int modifylog_files_open_or_create(struct mail_modify_log *log)
-{
-	int i, ret1, ret2;
-
-	for (i = 0; i < 2; i++) {
-		ret1 = mail_modifylog_open_and_verify(&log->file1);
-		ret2 = mail_modifylog_open_and_verify(&log->file2);
-
-		if (ret1 == 1 && ret2 != 1) {
-			log->head = log->tail = &log->file1;
-			return TRUE;
-		}
-
-		if (ret1 != 1 && ret2 == 1) {
-			log->head = log->tail = &log->file2;
-			return TRUE;
-		}
-
-		if (ret1 == 1 && ret2 == 1) {
-			/* both logs were opened ok, which shouldn't happen.
-			   safest thing to do is to mark both closed,
-			   delete them and recreate */
-			index_set_error(log->index,
-					"Index %s has both modify logs open",
-					log->index->filepath);
-			(void)modifylog_mark_full(&log->file1);
-			(void)modifylog_mark_full(&log->file2);
-
-			(void)unlink(log->file1.filepath);
-			(void)unlink(log->file2.filepath);
-
-			modifylog_close_file(&log->file1);
-			modifylog_close_file(&log->file2);
-		}
-
-		ret1 = modifylog_reuse_or_create_file(&log->file1);
-		if (ret1 == 1) {
-			log->head = log->tail = &log->file1;
-			return TRUE;
-		}
-		if (ret1 == -1)
-			break;
-
-		/* someone else probably just created the file */
-	}
-
-	if (ret1 == 0) {
-		/* we tried twice */
-		index_set_error(log->index, "Couldn't lock modify log file %s",
-				log->file1.filepath);
-	}
-	return FALSE;
-}
-
-static int modifylog_create_anon(struct modify_log_file *file)
-{
-	file->mmap_full_length = MODIFY_LOG_INITIAL_SIZE;
-	file->mmap_base = mmap_anon(file->mmap_full_length);
-	file->header = file->mmap_base;
-
-	if (file->mmap_base == MAP_FAILED)
-		return modifylog_set_syscall_error(file, "mmap_anon()");
-
-	mail_modifylog_init_header(file->log, file->mmap_base);
-
-	file->mmap_used_length = file->header->used_file_size;
-	file->synced_position = file->mmap_used_length;
-
-	file->anon_mmap = TRUE;
-	file->filepath = i_strdup_printf("(in-memory modify log for %s)",
-					 file->log->index->mailbox_path);
-	return TRUE;
-}
-
-int mail_modifylog_create(struct mail_index *index)
-{
-	struct mail_modify_log *log;
-	int ret;
-
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	log = mail_modifylog_new(index);
-
-	if (INDEX_IS_IN_MEMORY(index)) {
-		if (!modifylog_create_anon(&log->file1)) {
-			mail_modifylog_free(log);
-			return FALSE;
-		}
-	} else {
-		ret = modifylog_reuse_or_create_file(&log->file1);
-		if (ret == 0) {
-			index_set_error(log->index,
-				"Couldn't lock created modify log file %s",
-				log->file1.filepath);
-		}
-
-		if (ret <= 0 || !mmap_init_update(&log->file1)) {
-			/* fatal failure */
-			mail_modifylog_free(log);
-			return FALSE;
-		}
-	}
-
-	log->head = log->tail = &log->file1;
-	return TRUE;
-}
-
-int mail_modifylog_open_or_create(struct mail_index *index)
-{
-	struct mail_modify_log *log;
-
-	log = mail_modifylog_new(index);
-
-	if (!modifylog_files_open_or_create(log) ||
-	    !mmap_init_update(log->head)) {
-		/* fatal failure */
-		mail_modifylog_free(log);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-void mail_modifylog_free(struct mail_modify_log *log)
-{
-	log->index->modifylog = NULL;
-
-	modifylog_close_file(&log->file1);
-	modifylog_close_file(&log->file2);
-
-	i_free(log->file1.filepath);
-	i_free(log->file2.filepath);
-	i_free(log);
-}
-
-int mail_modifylog_sync_file(struct mail_modify_log *log, int *fsync_fd)
-{
-	struct modify_log_file *file = log->head;
-
-	*fsync_fd = -1;
-
-	if (!file->modified || file->anon_mmap)
-		return TRUE;
-
-	i_assert(file->mmap_base != NULL);
-
-	if (msync(file->mmap_base, file->mmap_used_length, MS_SYNC) < 0)
-		return modifylog_set_syscall_error(file, "msync()");
-
-	*fsync_fd = file->fd;
-	file->modified = FALSE;
-	return TRUE;
-}
-
-void mail_modifylog_notify_lock_drop(struct mail_modify_log *log)
-{
-	log->head->last_expunge = NULL;
-	log->head->last_flags = NULL;
-}
-
-/* if head file is closed, change it */
-static int modifylog_update_head(struct mail_modify_log *log)
-{
-	struct modify_log_file *file;
-
-	if (!mmap_update(log->head, FALSE))
-		return FALSE;
-
-	if (log->head->header->sync_id != SYNC_ID_FULL)
-		return TRUE;
-
-	i_assert(log->head == log->tail);
-
-	/* switch file */
-	file = log->head == &log->file1 ? &log->file2 : &log->file1;
-	if (file->fd == -1) {
-		if (mail_modifylog_open_and_verify(file) <= 0) {
-			modifylog_set_corrupted(file,
-				"Can't switch to open log file");
-			return FALSE;
-		}
-	}
-
-	if (!mmap_update(file, TRUE))
-		return FALSE;
-
-	/* we're non-synced */
-	file->synced_id = 0;
-	file->synced_position = sizeof(struct modify_log_header);
-	log->head = file;
-	return TRUE;
-}
-
-static int mmap_update_both(struct mail_modify_log *log)
-{
-	if (!modifylog_update_head(log))
-		return FALSE;
-
-	if (log->head != log->tail) {
-		if (!mmap_update(log->tail, FALSE))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-static int mail_modifylog_grow(struct modify_log_file *file)
-{
-	uoff_t new_fsize;
-	void *base;
-
-	new_fsize = (uoff_t)file->mmap_full_length + MODIFYLOG_GROW_SIZE;
-	i_assert(new_fsize < OFF_T_MAX);
-
-	if (file->anon_mmap) {
-		i_assert(new_fsize < SSIZE_T_MAX);
-
-		base = mremap_anon(file->mmap_base, file->mmap_full_length,
-				   (size_t)new_fsize, MREMAP_MAYMOVE);
-		if (base == MAP_FAILED) {
-			modifylog_set_syscall_error(file, "mremap_anon()");
-			return FALSE;
-		}
-
-		file->mmap_base = base;
-		file->mmap_full_length = (size_t)new_fsize;
-		return TRUE;
-	}
-
-	if (file_set_size(file->fd, (off_t)new_fsize) < 0)
-		return modifylog_set_syscall_error(file, "file_set_size()");
-
-	if (!mmap_update(file, TRUE))
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mail_modifylog_append(struct modify_log_file *file,
-				 struct modify_log_record **rec,
-				 int external_change)
-{
-	struct modify_log_record *destrec;
-
-	i_assert(file->log->index->lock_type == MAIL_LOCK_EXCLUSIVE);
-	i_assert(file->header->sync_id != SYNC_ID_FULL);
-	i_assert((*rec)->seq1 != 0);
-	i_assert((*rec)->uid1 != 0);
-
-	if (!external_change) {
-		if (file->log->cache_lock_counter !=
-		    file->log->index->excl_lock_counter) {
-			switch (modifylog_have_other_users(file->log, FALSE)) {
-			case 0:
-				/* we're the only one having this log open,
-				   no need for modify log. */
-				file->log->cache_have_others = FALSE;
-				file->log->cache_lock_counter =
-					file->log->index->excl_lock_counter;
-
-				*rec = NULL;
-				return TRUE;
-			case -1:
-				return FALSE;
-			default:
-				file->log->cache_have_others = TRUE;
-				file->log->cache_lock_counter =
-					file->log->index->excl_lock_counter;
-				break;
-			}
-		}
-
-		if (!file->log->cache_have_others) {
-			*rec = NULL;
-			return TRUE;
-		}
-	}
-
-	if (file->mmap_used_length == file->mmap_full_length) {
-		if (!mail_modifylog_grow(file))
-			return FALSE;
-	}
-
-	i_assert(file->header->used_file_size == file->mmap_used_length);
-	i_assert(file->mmap_used_length + sizeof(struct modify_log_record) <=
-		 file->mmap_full_length);
-
-	destrec = (struct modify_log_record *) ((char *) file->mmap_base +
-						file->mmap_used_length);
-	memcpy(destrec, *rec, sizeof(struct modify_log_record));
-
-	if (!external_change && file->header->sync_id == file->synced_id) {
-		file->synced_position += sizeof(struct modify_log_record);
-		file->synced_id++;
-	}
-
-	file->header->used_file_size += sizeof(struct modify_log_record);
-	file->mmap_used_length += sizeof(struct modify_log_record);
-
-	file->header->sync_id++;
-	file->modified = TRUE;
-
-	*rec = destrec;
-	return TRUE;
-}
-
-int mail_modifylog_add_expunges(struct mail_modify_log *log,
-				unsigned int first_seq, unsigned int last_seq,
-				unsigned int first_uid, unsigned int last_uid,
-				int external_change)
-{
-	struct modify_log_file *file;
-	struct modify_log_record rec, *recp;
-
-	if (!modifylog_update_head(log))
-		return FALSE;
-
-	file = log->head;
-
-	/* expunges must not be added when log isn't synced */
-	i_assert(external_change || file->synced_id == file->header->sync_id);
-
-	if (file->last_expunge != NULL &&
-	    file->last_expunge_external == external_change) {
-		if (last_seq+1 == file->last_expunge->seq1) {
-			i_assert(last_uid < file->last_expunge->uid1);
-			file->last_expunge->seq1 = first_seq;
-			file->last_expunge->uid1 = first_uid;
-			return TRUE;
-		} else if (first_seq == file->last_expunge->seq1) {
-			/* note that the weird looking logic above is correct.
-			   it's because of reordered seq numbers. */
-			i_assert(first_uid > file->last_expunge->uid2);
-			file->last_expunge->seq2 += (last_seq - first_seq) + 1;
-			file->last_expunge->uid2 = last_uid;
-			return TRUE;
-		}
-	}
-
-	rec.type = RECORD_TYPE_EXPUNGE;
-	rec.seq1 = first_seq; rec.seq2 = last_seq;
-	rec.uid1 = first_uid; rec.uid2 = last_uid;
-
-	recp = &rec;
-	if (!mail_modifylog_append(file, &recp, external_change))
-		return FALSE;
-
-        file->last_expunge_external = external_change;
-	file->last_expunge = recp;
-	return TRUE;
-}
-
-int mail_modifylog_add_flags(struct mail_modify_log *log, unsigned int seq,
-			     unsigned int uid, int external_change)
-{
-	struct modify_log_file *file;
-	struct modify_log_record rec, *recp;
-
-	if (!modifylog_update_head(log))
-		return FALSE;
-
-	file = log->head;
-
-	if (file->last_flags != NULL &&
-	    file->last_flags_external == external_change) {
-		if (seq+1 == file->last_flags->seq1) {
-			file->last_flags->seq1 = seq;
-			file->last_flags->uid1 = uid;
-			return TRUE;
-		} else if (seq-1 == file->last_flags->seq2) {
-			file->last_flags->seq2 = seq;
-			file->last_flags->uid2 = uid;
-			return TRUE;
-		}
-	}
-
-	rec.type = RECORD_TYPE_FLAGS_CHANGED;
-	rec.seq1 = rec.seq2 = seq;
-	rec.uid1 = rec.uid2 = uid;
-
-	recp = &rec;
-	if (!mail_modifylog_append(file, &recp, external_change))
-		return FALSE;
-
-        file->last_flags_external = external_change;
-	file->last_flags = recp;
-	return TRUE;
-}
-
-static void
-mail_modifylog_get_nonsynced_file(struct modify_log_file *file,
-				  const struct modify_log_record **arr,
-				  unsigned int *count)
-{
-	struct modify_log_record *end_rec;
-
-	i_assert(file->synced_position <= file->mmap_used_length);
-	i_assert(file->synced_position >= sizeof(struct modify_log_header));
-
-	*arr = (struct modify_log_record *) ((char *) file->mmap_base +
-					     file->synced_position);
-	end_rec = (struct modify_log_record *) ((char *) file->mmap_base +
-						file->mmap_used_length);
-	*count = (unsigned int) (end_rec - *arr);
-}
-
-int mail_modifylog_get_nonsynced(struct mail_modify_log *log,
-				 const struct modify_log_record **arr1,
-				 unsigned int *count1,
-				 const struct modify_log_record **arr2,
-				 unsigned int *count2)
-{
-	i_assert(log->index->lock_type != MAIL_LOCK_UNLOCK);
-
-	*arr1 = *arr2 = NULL;
-	*count1 = *count2 = 0;
-
-	if (!mmap_update_both(log))
-		return FALSE;
-
-	mail_modifylog_get_nonsynced_file(log->tail, arr1, count1);
-	if (log->head != log->tail)
-		mail_modifylog_get_nonsynced_file(log->head, arr2, count2);
-
-	return TRUE;
-}
-
-static int mail_modifylog_try_truncate(struct modify_log_file *file)
-{
-	if (modifylog_have_other_users(file->log, TRUE) != 0)
-		return FALSE;
-
-#ifdef DEBUG
-	mprotect(file->mmap_base, sizeof(struct modify_log_header),
-		 PROT_READ | PROT_WRITE);
-#endif
-	file->header->sync_id = 0;
-	file->header->used_file_size = sizeof(struct modify_log_header);
-
-	if (msync(file->mmap_base,
-		  sizeof(struct modify_log_header), MS_SYNC) < 0) {
-		modifylog_set_syscall_error(file, "msync()");
-		return FALSE;
-	}
-
-	file->synced_id = 0;
-	file->synced_position = sizeof(struct modify_log_header);
-
-	if (file_set_size(file->fd, MODIFY_LOG_INITIAL_SIZE) < 0)
-		modifylog_set_syscall_error(file, "file_set_size()");
-
-	return TRUE;
-}
-
-/* switches to active modify log, updating our sync mark to end of it */
-static int mail_modifylog_switch_file(struct mail_modify_log *log)
-{
-	struct modify_log_file *file;
-
-	(void)mail_modifylog_try_truncate(log->tail);
-
-	file = log->tail == &log->file1 ? &log->file2 : &log->file1;
-	if (file->fd == -1) {
-		if (mail_modifylog_open_and_verify(file) <= 0) {
-			modifylog_set_corrupted(file,
-				"Can't switch to open log file");
-			return FALSE;
-		}
-	}
-
-	modifylog_munmap(log->tail);
-
-	log->head = log->tail = file;
-	return mmap_init_update(log->head);
-}
-
-static int mail_modifylog_try_switch_file(struct mail_modify_log *log)
-{
-	struct modify_log_file *file;
-
-	if (log->head->anon_mmap)
-		return TRUE;
-
-	if (mail_modifylog_try_truncate(log->tail)) {
-		/* no need to switch, we're the only user and we just
-		   truncated it  */
-		return TRUE;
-	}
-
-	file = log->head == &log->file1 ? &log->file2 : &log->file1;
-	if (modifylog_reuse_or_create_file(file) != 1) {
-		/* locked or error, keep using the old log */
-		return TRUE;
-	}
-
-	if (!modifylog_mark_full(log->head))
-		return FALSE;
-
-	modifylog_munmap(log->head);
-
-	log->head = log->tail = file;
-	return mmap_init_update(log->head);
-}
-
-int mail_modifylog_mark_synced(struct mail_modify_log *log)
-{
-	i_assert(log->index->lock_type != MAIL_LOCK_UNLOCK);
-
-	if (!mmap_update_both(log))
-		return FALSE;
-
-	if (log->tail->header->sync_id == SYNC_ID_FULL) {
-		/* tail file is full, switch to next one */
-		return mail_modifylog_switch_file(log);
-	}
-
-	log->tail = log->head;
-	if (log->head->synced_id != log->head->header->sync_id) {
-		log->head->synced_id = log->head->header->sync_id;
-		log->head->synced_position = log->head->mmap_used_length;
-	}
-
-	if (log->head->mmap_used_length > MAX_MODIFYLOG_SIZE) {
-		/* if the other file isn't locked, switch to it */
-		return mail_modifylog_try_switch_file(log);
-	}
-
-	return TRUE;
-}
-
-static int compare_expunge(const void *p1, const void *p2)
-{
-	const struct modify_log_expunge *e1 = p1;
-	const struct modify_log_expunge *e2 = p2;
-
-	return e1->uid1 < e2->uid1 ? -1 : e1->uid1 > e2->uid1 ? 1 : 0;
-}
-
-static struct modify_log_record *modifylog_first(struct mail_modify_log *log)
-{
-	struct modify_log_file *file;
-        struct modify_log_record *rec;
-
-	file = log->tail;
-	rec = (struct modify_log_record *) ((char *) file->mmap_base +
-					    file->synced_position);
-	log->iterator_end = (struct modify_log_record *)
-		((char *) file->mmap_base + file->mmap_used_length);
-	return rec < log->iterator_end ? rec : NULL;
-}
-
-static struct modify_log_record *
-modifylog_next(struct mail_modify_log *log, struct modify_log_record *rec)
-{
-	struct modify_log_file *file;
-
-	rec++;
-	if (rec < log->iterator_end)
-		return rec;
-
-	file = log->head;
-	if ((char *) rec == (char *) file->mmap_base + file->mmap_used_length)
-		return NULL; /* end of head */
-
-	/* end of tail, jump to beginning of head */
-	rec = (struct modify_log_record *) ((char *) file->mmap_base +
-					    sizeof(struct modify_log_header));
-	log->iterator_end = (struct modify_log_record *)
-		((char *) file->mmap_base + file->mmap_used_length);
-	return rec < log->iterator_end ? rec : NULL;
-}
-
-static unsigned int
-modifylog_get_record_count_after(struct mail_modify_log *log,
-				 struct modify_log_record *rec)
-{
-	unsigned int count = 0;
-
-	if (log->head == log->tail ||
-	    IS_PTR_IN_RANGE(rec, log->head->mmap_base,
-			    log->head->mmap_used_length)) {
-		/* only head */
-		count = (log->head->mmap_used_length -
-			 MODIFYLOG_FILE_POSITION(log->head, rec)) /
-			sizeof(struct modify_log_record);
-	} else {
-		/* tail */
-		count = (log->tail->mmap_used_length -
-			 MODIFYLOG_FILE_POSITION(log->tail, rec)) /
-			sizeof(struct modify_log_record);
-
-		if (log->head != log->tail) {
-			/* + head */
-			count += (log->tail->mmap_used_length -
-				  sizeof(struct modify_log_header)) /
-				sizeof(struct modify_log_record);
-		}
-	}
-
-	return count;
-}
-
-const struct modify_log_expunge *
-mail_modifylog_seq_get_expunges(struct mail_modify_log *log,
-				unsigned int first_seq,
-				unsigned int last_seq,
-				unsigned int *expunges_before)
-{
-	struct modify_log_record *rec;
-	struct modify_log_expunge expunge, *expunges;
-	buffer_t *buf;
-	size_t count;
-	unsigned int before, max_records;
-
-	i_assert(log->index->lock_type != MAIL_LOCK_UNLOCK);
-
-	*expunges_before = 0;
-
-	if (!mmap_update_both(log))
-		return NULL;
-
-	/* find the first expunged message that affects our range */
-	rec = modifylog_first(log);
-	while (rec != NULL) {
-		if (rec->type == RECORD_TYPE_EXPUNGE && rec->seq1 <= last_seq)
-			break;
-
-		rec = modifylog_next(log, rec);
-	}
-
-	if (rec == NULL) {
-		/* none found */
-		return &no_expunges;
-	}
-
-	/* allocate memory for the returned array. the file size - synced
-	   position should be quite near the amount of memory we need, unless
-	   there's lots of FLAGS_CHANGED records which is why there's the
-	   second check to make sure it's not unneededly large. */
-	max_records = modifylog_get_record_count_after(log, rec);
-	if (max_records > last_seq - first_seq + 1)
-		max_records = last_seq - first_seq + 1;
-
-	i_assert((max_records+1) <
-		 SSIZE_T_MAX / sizeof(struct modify_log_expunge));
-	buf = buffer_create_static_hard(pool_datastack_create(),
-					(max_records+1) *
-					sizeof(struct modify_log_expunge));
-
-	before = 0;
-	for (; rec != NULL; rec = modifylog_next(log, rec)) {
-		if (rec->type != RECORD_TYPE_EXPUNGE)
-			continue;
-
-		if (rec->seq2 < first_seq) {
-			/* before our range */
-			before += rec->seq2 - rec->seq1 + 1;
-		} else if (rec->seq1 <= last_seq && rec->seq2 >= first_seq) {
-			/* within our range, at least partially */
-			if (max_records-- == 0) {
-				/* log contains more data than it should
-				   have - must be corrupted. */
-				modifylog_set_corrupted(log->tail,
-					"Contains more data than expected");
-				return NULL;
-			}
-
-			if (rec->seq1 < first_seq) {
-				/* partial initial match, update
-				   before-counter */
-				before += first_seq - rec->seq1;
-				expunge.seq_count = rec->seq2 - first_seq + 1;
-			} else {
-				expunge.seq_count = rec->seq2 - rec->seq1 + 1;
-			}
-
-			expunge.uid1 = rec->uid1;
-			expunge.uid2 = rec->uid2;
-			buffer_append(buf, &expunge, sizeof(expunge));
-		}
-
-		if (rec->seq1 <= last_seq) {
-			/* update the seq. numbers so they can be compared */
-			last_seq -= I_MIN(rec->seq2, last_seq) -
-				rec->seq1 + 1;
-
-			if (rec->seq1 < first_seq) {
-				first_seq -= I_MIN(rec->seq2, first_seq-1) -
-					rec->seq1 + 1;
-			}
-		}
-	}
-
-	/* terminate the array */
-	buffer_set_used_size(buf, buffer_get_used_size(buf) + sizeof(expunge));
-
-	/* extract the array from buffer */
-	count = buffer_get_used_size(buf) / sizeof(expunge);
-	expunges = buffer_free_without_data(buf);
-
-	/* sort the UID array, not including the terminating 0 */
-	qsort(expunges, count-1, sizeof(expunge), compare_expunge);
-
-	*expunges_before = before;
-	return expunges;
-}
-
-const struct modify_log_expunge *
-mail_modifylog_uid_get_expunges(struct mail_modify_log *log,
-				unsigned int first_uid,
-				unsigned int last_uid,
-				unsigned int *expunges_before)
-{
-	/* pretty much copy&pasted from sequence code above ..
-	   kind of annoying */
-	struct modify_log_record *rec;
-	struct modify_log_expunge expunge, *expunges;
-	buffer_t *buf;
-	size_t count;
-	unsigned int before, max_records;
-
-	i_assert(log->index->lock_type != MAIL_LOCK_UNLOCK);
-
-	*expunges_before = 0;
-
-	if (!mmap_update_both(log))
-		return NULL;
-
-	/* find the first expunged message that affects our range */
-	rec = modifylog_first(log);
-	while (rec != NULL) {
-		if (rec->type == RECORD_TYPE_EXPUNGE && rec->uid1 <= last_uid)
-			break;
-
-		rec = modifylog_next(log, rec);
-	}
-
-	if (rec == NULL) {
-		/* none found */
-		return &no_expunges;
-	}
-
-	/* allocate memory for the returned array. the file size - synced
-	   position should be quite near the amount of memory we need, unless
-	   there's lots of FLAGS_CHANGED records which is why there's the
-	   second check to make sure it's not unneededly large. */
-	max_records = modifylog_get_record_count_after(log, rec);
-	if (max_records > last_uid - first_uid + 1)
-		max_records = last_uid - first_uid + 1;
-
-	i_assert((max_records+1) <
-		 SSIZE_T_MAX / sizeof(struct modify_log_expunge));
-	buf = buffer_create_static_hard(pool_datastack_create(),
-					(max_records+1) *
-					sizeof(struct modify_log_expunge));
-
-	before = 0;
-	for (; rec != NULL; rec = modifylog_next(log, rec)) {
-		if (rec->type != RECORD_TYPE_EXPUNGE)
-			continue;
-
-                if (rec->uid2 < first_uid) {
-			/* before our range */
-			before += rec->seq2 - rec->seq1 + 1;
-		} else if (rec->uid1 <= last_uid && rec->uid2 >= first_uid) {
-			/* within our range, at least partially */
-			if (max_records-- == 0) {
-				/* log contains more data than it should
-				   have - must be corrupted. */
-				modifylog_set_corrupted(log->tail,
-					"Contains more data than expected");
-				return NULL;
-			}
-
-			expunge.uid1 = rec->uid1;
-			expunge.uid2 = rec->uid2;
-			expunge.seq_count = rec->seq2 -rec->seq1 + 1;
-			buffer_append(buf, &expunge, sizeof(expunge));
-		}
-	}
-
-	/* terminate the array */
-	buffer_set_used_size(buf, buffer_get_used_size(buf) + sizeof(expunge));
-
-	/* extract the array from buffer */
-	count = buffer_get_used_size(buf) / sizeof(expunge);
-	expunges = buffer_free_without_data(buf);
-
-	/* sort the UID array, not including the terminating 0 */
-	qsort(expunges, count-1, sizeof(expunge), compare_expunge);
-
-	*expunges_before = before;
-	return expunges;
-}
-
-static unsigned int
-modifylog_file_get_expunge_count(struct modify_log_file *file)
-{
-	struct modify_log_record *rec, *end_rec;
-	unsigned int expunges;
-
-	/* find the first expunged message that affects our range */
-	rec = (struct modify_log_record *) ((char *) file->mmap_base +
-					    file->synced_position);
-	end_rec = (struct modify_log_record *) ((char *) file->mmap_base +
-						file->mmap_used_length);
-
-	expunges = 0;
-	while (rec < end_rec) {
-		if (rec->type == RECORD_TYPE_EXPUNGE)
-			expunges += rec->seq2 - rec->seq1 + 1;
-		rec++;
-	}
-
-	return expunges;
-}
-
-unsigned int mail_modifylog_get_expunge_count(struct mail_modify_log *log)
-{
-	unsigned int expunges;
-
-	i_assert(log->index->lock_type != MAIL_LOCK_UNLOCK);
-
-	if (!mmap_update_both(log))
-		return 0;
-
-	expunges = modifylog_file_get_expunge_count(log->tail);
-	if (log->tail != log->head)
-		expunges += modifylog_file_get_expunge_count(log->head);
-
-	return expunges;
-}
--- a/src/lib-index/mail-modifylog.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-#ifndef __MAIL_MODIFYLOG_H
-#define __MAIL_MODIFYLOG_H
-
-enum modify_log_record_type {
-	RECORD_TYPE_EXPUNGE,
-	RECORD_TYPE_FLAGS_CHANGED
-};
-
-/* if sync_id has this value, the log file is full and should be
-   deleted or reused. */
-#define SYNC_ID_FULL ((unsigned int)-1)
-
-struct modify_log_header {
-	unsigned int indexid;
-	unsigned int sync_id;
-	uoff_t used_file_size;
-};
-
-struct modify_log_record {
-	unsigned int type;
-	unsigned int seq1, seq2;
-	unsigned int uid1, uid2;
-};
-
-/* for mail_modifylog_*_get_expunges() */
-struct modify_log_expunge {
-	unsigned int uid1, uid2; /* NOTE: may be outside wanted range */
-	unsigned int seq_count;
-};
-
-/* NOTE: All these functions require the index file to be locked. */
-
-int mail_modifylog_create(struct mail_index *index);
-int mail_modifylog_open_or_create(struct mail_index *index);
-void mail_modifylog_free(struct mail_modify_log *log);
-
-/* Append EXPUGE or FLAGS entry to modify log. Index must be exclusively
-   locked before calling these functions, and modifylog must have been
-   marked synced within the same lock. */
-int mail_modifylog_add_expunges(struct mail_modify_log *log,
-				unsigned int first_seq, unsigned int last_seq,
-				unsigned int first_uid, unsigned int last_uid,
-				int external_change);
-int mail_modifylog_add_flags(struct mail_modify_log *log, unsigned int seq,
-			     unsigned int uid, int external_change);
-
-/* Synchronize the data into disk */
-int mail_modifylog_sync_file(struct mail_modify_log *log, int *fsync_fd);
-
-/* Must be called when exclusive lock is dropped from index. */
-void mail_modifylog_notify_lock_drop(struct mail_modify_log *log);
-
-/* Updates arr and count parameters to list nonsynced log entries.
-   Returns TRUE if successful. */
-int mail_modifylog_get_nonsynced(struct mail_modify_log *log,
-				 const struct modify_log_record **arr1,
-				 unsigned int *count1,
-				 const struct modify_log_record **arr2,
-				 unsigned int *count2);
-
-/* Marks the modify log as being synced with in-memory state. */
-int mail_modifylog_mark_synced(struct mail_modify_log *log);
-
-/* Finds expunged messages for the given sequence range, and number of
-   expunged messages before the range. Returns 0,0 terminated list of
-   expunged UIDs, or NULL if error occured.
-
-   Note that returned UID range may not be exact for first returned
-   expunge record. For example fetching range 9:10 may return
-   expunges_before=8, {uid1=1, uid2=9, seq_count=1} if only message 10
-   exists.
-
-   Also the last expunge record's both uid and seq_count ranges may go
-   past last_seq */
-const struct modify_log_expunge *
-mail_modifylog_seq_get_expunges(struct mail_modify_log *log,
-				unsigned int first_seq,
-				unsigned int last_seq,
-				unsigned int *expunges_before);
-
-/* Like above, but for given UID range. expunges_before is treated a bit
-   differently however. It specifies the number of messages deleted before
-   the first returned expunge-record, which may partially be before our
-   wanted range. For example fetching range 9:10 may return
-   expunges_before=0, {uid1=1, uid2=9, seq_count=9} if only message 10
-   exists. This is because we have no idea how many messages there are
-   between UIDs since they're not guaranteed to be contiguous. */
-const struct modify_log_expunge *
-mail_modifylog_uid_get_expunges(struct mail_modify_log *log,
-				unsigned int first_uid,
-				unsigned int last_uid,
-				unsigned int *expunges_before);
-
-/* Get number of non-synced expunges in modify log. */
-unsigned int mail_modifylog_get_expunge_count(struct mail_modify_log *log);
-
-#endif
--- a/src/lib-index/maildir/maildir-build.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/* Copyright (C) 2002-2003 Timo Sirainen */
-
-#include "lib.h"
-#include "maildir-index.h"
-#include "mail-cache.h"
-
-int maildir_cache_update_file(struct mail_cache_transaction_ctx **trans_ctx,
-			      struct mail_index *index,
-			      struct mail_index_record *rec, const char *fname,
-			      int new_dir)
-{
-	enum mail_cache_field cached_fields;
-        enum mail_index_record_flag index_flags;
-	uoff_t virtual_size;
-	const char *p;
-
-	if (*trans_ctx == NULL) {
-		if (mail_cache_transaction_begin(index->cache,
-						 TRUE, trans_ctx) <= 0)
-			return FALSE;
-	}
-
-	cached_fields = mail_cache_get_fields(index->cache, rec);
-	if ((cached_fields & MAIL_CACHE_INDEX_FLAGS) == 0) {
-		/* always set index flags */
-		index_flags = new_dir ? MAIL_INDEX_FLAG_MAILDIR_NEW : 0;
-		if (!mail_cache_add(*trans_ctx, rec, MAIL_CACHE_INDEX_FLAGS,
-				    &index_flags, sizeof(index_flags)))
-			return FALSE;
-	}
-
-	/* set virtual size if found from file name */
-	p = strstr(fname, ",W=");
-	if (p != NULL && (cached_fields & MAIL_CACHE_VIRTUAL_FULL_SIZE) == 0) {
-		p += 3;
-		virtual_size = 0;
-		while (*p >= '0' && *p <= '9') {
-			virtual_size = virtual_size * 10 + (*p - '0');
-			p++;
-		}
-
-		if (*p == ':' || *p == ',' || *p != '\0') {
-			if (!mail_cache_add(*trans_ctx, rec,
-					    MAIL_CACHE_VIRTUAL_FULL_SIZE,
-					    &virtual_size,
-					    sizeof(virtual_size)))
-				return FALSE;
-		}
-	}
-
-	if ((cached_fields & MAIL_CACHE_LOCATION) == 0) {
-		/* always set location */
-		if (!mail_cache_add(*trans_ctx, rec, MAIL_CACHE_LOCATION,
-				    fname, strlen(fname)+1))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-int maildir_index_append_file(struct mail_cache_transaction_ctx **trans_ctx,
-			      struct mail_index *index, const char *fname,
-			      int new_dir)
-{
-	struct mail_index_record *rec;
-
-	rec = index->append(index);
-	if (rec == NULL)
-		return FALSE;
-
-	/* set message flags from file name */
-	rec->msg_flags = maildir_filename_get_flags(fname, 0);
-	mail_index_mark_flag_changes(index, rec, 0, rec->msg_flags);
-
-        return maildir_cache_update_file(trans_ctx, index, rec, fname, new_dir);
-}
--- a/src/lib-index/maildir/maildir-clean.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "maildir-index.h"
-
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-/* Clean files from tmp/ if they're older than 36 hours */
-#define MAILDIR_CLEANUP_TIME (60 * 60 * 36)
-
-void maildir_clean_tmp(const char *dir)
-{
-	time_t cleanup_time = ioloop_time - MAILDIR_CLEANUP_TIME;
-	DIR *dirp;
-	struct dirent *d;
-	struct stat st;
-	const char *path;
-
-	dirp = opendir(dir);
-	if (dirp == NULL) {
-		i_error("opendir(%s) failed: %m", dir);
-		return;
-	}
-
-	while ((d = readdir(dirp)) != NULL) {
-		if (strcmp(d->d_name, ".") == 0 ||
-		    strcmp(d->d_name, "..") == 0)
-			continue;
-
-		t_push();
-		path = t_strconcat(dir, "/", d->d_name, NULL);
-		if (stat(path, &st) < 0) {
-			if (errno != ENOENT)
-				i_error("stat(%s) failed: %m", path);
-		} else if (st.st_mtime < cleanup_time &&
-			   st.st_atime < cleanup_time &&
-			   !S_ISDIR(st.st_mode)) {
-			if (unlink(path) < 0 && errno != ENOENT)
-				i_error("unlink(%s) failed: %m", path);
-		}
-		t_pop();
-	}
-
-	if (closedir(dirp) < 0)
-		i_error("closedir(%s) failed: %m", dir);
-}
--- a/src/lib-index/maildir/maildir-expunge.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "maildir-index.h"
-#include "mail-index-util.h"
-
-#include <unistd.h>
-
-static int do_expunge(struct mail_index *index, const char *path, void *context)
-{
-	int *found = context;
-
-	if (unlink(path) < 0) {
-		if (errno == ENOENT)
-			return 0;
-		if (errno == EACCES) {
-			index->mailbox_readonly = TRUE;
-			return 1;
-		}
-
-		index_set_error(index, "unlink(%s) failed: %m", path);
-		return -1;
-	}
-
-	*found = TRUE;
-	return 1;
-}
-
-int maildir_expunge_mail(struct mail_index *index,
-			 struct mail_index_record *rec)
-{
-	int found = FALSE;
-
-	if (!maildir_file_do(index, rec, do_expunge, &found))
-		return FALSE;
-
-	if (found) {
-		/* if we're in out-of-space condition, reset it since we'll
-		   probably have enough space now. */
-		index->maildir_keep_new = FALSE;
-		if (index->next_dirty_flags_flush != 0)
-			index->next_dirty_flags_flush = ioloop_time;
-
-		/* cur/ was updated, set it dirty-synced */
-		index->sync_dirty_stamp = ioloop_time;
-		index->sync_stamp = ioloop_time;
-	}
-	return TRUE;
-}
--- a/src/lib-index/maildir/maildir-index.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,413 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "hash.h"
-#include "hostpid.h"
-#include "str.h"
-#include "maildir-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <time.h>
-
-extern struct mail_index maildir_index;
-
-static int maildir_index_open(struct mail_index *index,
-			      enum mail_index_open_flags flags)
-{
-	maildir_clean_tmp(t_strconcat(index->mailbox_path, "/tmp", NULL));
-	return mail_index_open(index, flags);
-}
-
-const char *maildir_get_location(struct mail_index *index,
-				 struct mail_index_record *rec, int *new_dir)
-{
-	const char *fname, *new_fname;
-
-	if (new_dir != NULL)
-		*new_dir = FALSE;
-
-	if (index->new_filenames != NULL) {
-		/* this has the most up-to-date filename */
-		new_fname = hash_lookup(index->new_filenames,
-					POINTER_CAST(rec->uid));
-		if (new_fname != NULL) {
-			if (*new_fname == '/') {
-				new_fname++;
-				if (new_dir != NULL)
-					*new_dir = TRUE;
-			}
-			return new_fname;
-		}
-	}
-
-	/* cache file file should give us at least the base name. */
-	fname = mail_cache_lookup_string_field(index->cache, rec,
-					       MAIL_CACHE_LOCATION);
-	if (fname == NULL) {
-		/* Not cached, we'll have to resync the directory. */
-		return NULL;
-	}
-
-	if (new_dir != NULL) {
-		*new_dir = (mail_cache_get_index_flags(index->cache, rec) &
-			    MAIL_INDEX_FLAG_MAILDIR_NEW) != 0;
-	}
-
-	return fname;
-}
-
-static int
-maildir_file_do_try(struct mail_index *index, struct mail_index_record *rec,
-		    const char **fname,
-		    maildir_file_do_func *func, void *context)
-{
-	const char *path;
-	int ret, new_dir;
-
-	*fname = maildir_get_location(index, rec, &new_dir);
-	if (*fname == NULL)
-		return 0;
-
-	if (new_dir) {
-		/* probably in new/ dir */
-		path = t_strconcat(index->mailbox_path, "/new/", *fname, NULL);
-		ret = func(index, path, context);
-		if (ret != 0)
-			return ret;
-	}
-
-	path = t_strconcat(index->mailbox_path, "/cur/", *fname, NULL);
-	return func(index, path, context);
-}
-
-int maildir_file_do(struct mail_index *index, struct mail_index_record *rec,
-		    maildir_file_do_func *func, void *context)
-{
-	const char *fname;
-	int i, ret, found;
-
-	ret = maildir_file_do_try(index, rec, &fname, func, context);
-	for (i = 0; i < 10 && ret == 0; i++) {
-		/* file is either renamed or deleted. sync the maildir and
-		   see which one. if file appears to be renamed constantly,
-		   don't try to open it more than 10 times. */
-		fname = t_strdup(fname);
-		if (!maildir_index_sync_readonly(index, fname, &found))
-			return FALSE;
-
-		if (!found && fname != NULL)
-			return TRUE;
-
-		ret = maildir_file_do_try(index, rec, &fname, func, context);
-	}
-
-	return ret >= 0;
-}
-
-const char *maildir_generate_tmp_filename(const struct timeval *tv)
-{
-	static unsigned int create_count = 0;
-	static time_t first_stamp = 0;
-
-	if (first_stamp == 0 || first_stamp == ioloop_time) {
-		/* it's possible that within last second another process had
-		   the same UID as us. Use usecs to make sure we don't create
-		   duplicate base name. */
-		first_stamp = ioloop_time;
-		return t_strdup_printf("%s.P%sQ%uM%s.%s",
-				       dec2str(tv->tv_sec), my_pid,
-				       create_count++,
-				       dec2str(tv->tv_usec), my_hostname);
-	} else {
-		/* Don't bother with usecs. Saves a bit space :) */
-		return t_strdup_printf("%s.P%sQ%u.%s",
-				       dec2str(tv->tv_sec), my_pid,
-				       create_count++, my_hostname);
-	}
-}
-
-int maildir_create_tmp(struct mail_index *index, const char *dir, mode_t mode,
-		       const char **fname)
-{
-	const char *path, *tmp_fname;
-	struct stat st;
-	struct timeval *tv, tv_now;
-	pool_t pool;
-	int fd;
-
-	tv = &ioloop_timeval;
-	pool = pool_alloconly_create("maildir_tmp", 4096);
-	for (;;) {
-		p_clear(pool);
-		tmp_fname = maildir_generate_tmp_filename(tv);
-
-		path = p_strconcat(pool, dir, "/", tmp_fname, NULL);
-		if (stat(path, &st) < 0 && errno == ENOENT) {
-			/* doesn't exist */
-			mode_t old_mask = umask(0);
-			fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
-			umask(old_mask);
-			if (fd != -1 || errno != EEXIST)
-				break;
-		}
-
-		/* wait and try again - very unlikely */
-		sleep(2);
-		tv = &tv_now;
-		if (gettimeofday(&tv_now, NULL) < 0)
-			i_fatal("gettimeofday(): %m");
-	}
-
-	*fname = t_strdup(path);
-	if (fd == -1)
-		index_file_set_syscall_error(index, path, "open()");
-
-	pool_unref(pool);
-	return fd;
-}
-
-enum mail_flags maildir_filename_get_flags(const char *fname,
-					   enum mail_flags default_flags)
-{
-	const char *info;
-	enum mail_flags flags;
-
-	info = strchr(fname, ':');
-	if (info == NULL || info[1] != '2' || info[2] != ',')
-		return default_flags;
-
-	flags = 0;
-	for (info += 3; *info != '\0' && *info != ','; info++) {
-		switch (*info) {
-		case 'R': /* replied */
-			flags |= MAIL_ANSWERED;
-			break;
-		case 'S': /* seen */
-			flags |= MAIL_SEEN;
-			break;
-		case 'T': /* trashed */
-			flags |= MAIL_DELETED;
-			break;
-		case 'D': /* draft */
-			flags |= MAIL_DRAFT;
-			break;
-		case 'F': /* flagged */
-			flags |= MAIL_FLAGGED;
-			break;
-		default:
-			if (*info >= 'a' && *info <= 'z') {
-				/* custom flag */
-				flags |= 1 << (MAIL_CUSTOM_FLAG_1_BIT +
-					       *info-'a');
-				break;
-			}
-
-			/* unknown flag - ignore */
-			break;
-		}
-	}
-
-	return flags;
-}
-
-const char *maildir_filename_set_flags(const char *fname, enum mail_flags flags)
-{
-	string_t *flags_str;
-	const char *info, *oldflags;
-	int i, nextflag;
-
-	/* remove the old :info from file name, and get the old flags */
-	info = strrchr(fname, ':');
-	if (info != NULL && strrchr(fname, '/') > info)
-		info = NULL;
-
-	oldflags = "";
-	if (info != NULL) {
-		fname = t_strdup_until(fname, info);
-		if (info[1] == '2' && info[2] == ',')
-			oldflags = info+3;
-	}
-
-	/* insert the new flags between old flags. flags must be sorted by
-	   their ASCII code. unknown flags are kept. */
-	flags_str = t_str_new(256);
-	str_append(flags_str, fname);
-	str_append(flags_str, ":2,");
-	for (;;) {
-		/* skip all known flags */
-		while (*oldflags == 'D' || *oldflags == 'F' ||
-		       *oldflags == 'R' || *oldflags == 'S' ||
-		       *oldflags == 'T' ||
-		       (*oldflags >= 'a' && *oldflags <= 'z'))
-			oldflags++;
-
-		nextflag = *oldflags == '\0' || *oldflags == ',' ? 256 :
-			(unsigned char) *oldflags;
-
-		if ((flags & MAIL_DRAFT) && nextflag > 'D') {
-			str_append_c(flags_str, 'D');
-			flags &= ~MAIL_DRAFT;
-		}
-		if ((flags & MAIL_FLAGGED) && nextflag > 'F') {
-			str_append_c(flags_str, 'F');
-			flags &= ~MAIL_FLAGGED;
-		}
-		if ((flags & MAIL_ANSWERED) && nextflag > 'R') {
-			str_append_c(flags_str, 'R');
-			flags &= ~MAIL_ANSWERED;
-		}
-		if ((flags & MAIL_SEEN) && nextflag > 'S') {
-			str_append_c(flags_str, 'S');
-			flags &= ~MAIL_SEEN;
-		}
-		if ((flags & MAIL_DELETED) && nextflag > 'T') {
-			str_append_c(flags_str, 'T');
-			flags &= ~MAIL_DELETED;
-		}
-
-		if ((flags & MAIL_CUSTOM_FLAGS_MASK) && nextflag > 'a') {
-			for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-				if (flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT)))
-					str_append_c(flags_str, 'a' + i);
-			}
-			flags &= ~MAIL_CUSTOM_FLAGS_MASK;
-		}
-
-		if (*oldflags == '\0' || *oldflags == ',')
-			break;
-
-		str_append_c(flags_str, *oldflags);
-		oldflags++;
-	}
-
-	if (*oldflags == ',') {
-		/* another flagset, we don't know about these, just keep them */
-		while (*oldflags != '\0')
-			str_append_c(flags_str, *oldflags++);
-	}
-
-	return str_c(flags_str);
-}
-
-void maildir_index_update_filename(struct mail_index *index, unsigned int uid,
-				   const char *fname, int new_dir)
-{
-	const char *new_fname, *old_fname;
-
-	if (index->new_filename_pool == NULL) {
-		index->new_filename_pool =
-			pool_alloconly_create("Maildir filenames", 10240);
-	}
-	if (index->new_filenames == NULL) {
-		index->new_filenames =
-			hash_create(system_pool, index->new_filename_pool, 0,
-				    NULL, NULL);
-	}
-
-	t_push();
-	new_fname = !new_dir ? fname : t_strconcat("/", fname, NULL);
-	old_fname = hash_lookup(index->new_filenames, POINTER_CAST(uid));
-	if (old_fname == NULL || strcmp(old_fname, new_fname) != 0) {
-		hash_insert(index->new_filenames, POINTER_CAST(uid),
-                            p_strdup(index->new_filename_pool, new_fname));
-	}
-	t_pop();
-}
-
-struct mail_index *
-maildir_index_alloc(const char *maildir, const char *index_dir,
-		    const char *control_dir)
-{
-	struct mail_index *index;
-
-	i_assert(maildir != NULL);
-	i_assert(control_dir != NULL);
-
-	index = i_new(struct mail_index, 1);
-	memcpy(index, &maildir_index, sizeof(struct mail_index));
-
-	index->maildir_lock_fd = -1;
-	index->mailbox_path = i_strdup(maildir);
-	index->control_dir = i_strdup(control_dir);
-	index->mailbox_readonly = access(maildir, W_OK) < 0;
-	mail_index_init(index, index_dir);
-	return index;
-}
-
-static void maildir_index_free(struct mail_index *index)
-{
-	if (index->new_filenames != NULL)
-		hash_destroy(index->new_filenames);
-	if (index->new_filename_pool != NULL)
-		pool_unref(index->new_filename_pool);
-
-	mail_index_close(index);
-	i_free(index->dir);
-	i_free(index->mailbox_path);
-	i_free(index->control_dir);
-	i_free(index);
-}
-
-static int do_get_received_date(struct mail_index *index,
-				const char *path, void *context)
-{
-	time_t *date = context;
-	struct stat st;
-
-	if (stat(path, &st) < 0) {
-		if (errno == ENOENT)
-			return 0;
-		index_file_set_syscall_error(index, path, "stat()");
-		return -1;
-	}
-
-	*date = st.st_mtime;
-	return 1;
-}
-
-static time_t maildir_get_received_date(struct mail_index *index,
-					struct mail_index_record *rec)
-{
-	time_t date;
-
-	/* try getting it from cache */
-	if (mail_cache_copy_fixed_field(index->cache, rec,
-					MAIL_CACHE_RECEIVED_DATE,
-					&date, sizeof(date)))
-		return date;
-
-	date = (time_t)-1;
-	if (!maildir_file_do(index, rec, do_get_received_date, &date))
-		return (time_t)-1;
-
-	return date;
-}
-
-struct mail_index maildir_index = {
-	maildir_index_open,
-	maildir_index_free,
-	mail_index_set_lock,
-	mail_index_try_lock,
-        mail_index_set_lock_notify_callback,
-	mail_index_rebuild,
-	mail_index_fsck,
-	maildir_index_sync,
-	mail_index_get_header,
-	mail_index_lookup,
-	mail_index_next,
-        mail_index_lookup_uid_range,
-	maildir_open_mail,
-	maildir_get_received_date,
-	mail_index_expunge,
-	maildir_index_update_flags,
-	mail_index_append,
-	mail_index_get_last_error,
-	mail_index_get_last_error_text,
-
-	MAIL_INDEX_PRIVATE_FILL
-};
--- a/src/lib-index/maildir/maildir-index.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-#ifndef __MAILDIR_INDEX_H
-#define __MAILDIR_INDEX_H
-
-struct mail_cache_transaction_ctx;
-
-#include <sys/time.h>
-#include "mail-index.h"
-
-/* How often to try to flush dirty flags. */
-#define MAILDIR_DIRTY_FLUSH_TIMEOUT (60*5)
-
-/* Return -1 = error, 0 = file not found, 1 = ok */
-typedef int maildir_file_do_func(struct mail_index *index,
-				 const char *path, void *context);
-
-struct mail_index *
-maildir_index_alloc(const char *maildir, const char *index_dir,
-		    const char *control_dir);
-
-/* Return new filename base to save into tmp/ */
-const char *maildir_generate_tmp_filename(const struct timeval *tv);
-int maildir_create_tmp(struct mail_index *index, const char *dir, mode_t mode,
-		       const char **path);
-
-const char *maildir_get_location(struct mail_index *index,
-				 struct mail_index_record *rec, int *new_dir);
-int maildir_file_do(struct mail_index *index, struct mail_index_record *rec,
-		    maildir_file_do_func *func, void *context);
-enum mail_flags maildir_filename_get_flags(const char *fname,
-					   enum mail_flags default_flags);
-const char *maildir_filename_set_flags(const char *fname,
-				       enum mail_flags flags);
-void maildir_index_update_filename(struct mail_index *index, unsigned int uid,
-				   const char *fname, int new_dir);
-
-int maildir_index_sync_readonly(struct mail_index *index,
-				const char *fname, int *found);
-int maildir_index_sync(struct mail_index *index, int minimal_sync,
-		       enum mail_lock_type lock_type, int *changes);
-
-int maildir_cache_update_file(struct mail_cache_transaction_ctx **trans_ctx,
-			      struct mail_index *index,
-			      struct mail_index_record *rec, const char *fname,
-			      int new_dir);
-int maildir_index_append_file(struct mail_cache_transaction_ctx **trans_ctx,
-			      struct mail_index *index, const char *fname,
-			      int new_dir);
-int maildir_index_update_flags(struct mail_index *index,
-			       struct mail_index_record *rec, unsigned int seq,
-			       enum modify_type modify_type,
-			       enum mail_flags flags, int external_change);
-int maildir_try_flush_dirty_flags(struct mail_index *index, int force);
-
-struct istream *maildir_open_mail(struct mail_index *index,
-				  struct mail_index_record *rec,
-				  time_t *received_date, int *deleted);
-
-int maildir_expunge_mail(struct mail_index *index,
-			 struct mail_index_record *rec);
-
-void maildir_clean_tmp(const char *dir);
-
-#endif
--- a/src/lib-index/maildir/maildir-open.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "istream.h"
-#include "maildir-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-static int do_open(struct mail_index *index, const char *path, void *context)
-{
-	int *fd = context;
-
-	*fd = open(path, O_RDONLY);
-	if (*fd != -1)
-		return 1;
-	if (errno == ENOENT)
-		return 0;
-
-	index_file_set_syscall_error(index, path, "open()");
-	return -1;
-}
-
-struct istream *maildir_open_mail(struct mail_index *index,
-				  struct mail_index_record *rec,
-				  time_t *received_date, int *deleted)
-{
-	struct stat st;
-	int fd;
-
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-
-	*deleted = FALSE;
-
-	/* check for inconsistency here, to avoid extra error messages */
-	if (index->inconsistent)
-		return NULL;
-
-	fd = -1;
-	if (!maildir_file_do(index, rec, do_open, &fd))
-		return NULL;
-
-	if (fd == -1) {
-		*deleted = TRUE;
-		return NULL;
-	}
-
-	if (received_date != NULL) {
-		if (fstat(fd, &st) == 0)
-			*received_date = st.st_mtime;
-	}
-
-	if (index->mail_read_mmaped) {
-		return i_stream_create_mmap(fd, default_pool,
-					    MAIL_MMAP_BLOCK_SIZE, 0, 0, TRUE);
-	} else {
-		return i_stream_create_file(fd, default_pool,
-					    MAIL_READ_BLOCK_SIZE, TRUE);
-	}
-}
--- a/src/lib-index/maildir/maildir-sync.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1393 +0,0 @@
-/* Copyright (C) 2002-2003 Timo Sirainen */
-
-/*
-   Here's a description of how we handle Maildir synchronization and
-   it's problems:
-
-   We want to be as efficient as we can. The most efficient way to
-   check if changes have occured is to stat() the new/ and cur/
-   directories and uidlist file - if their mtimes haven't changed,
-   there's no changes and we don't need to do anything.
-
-   Problem 1: Multiple changes can happen within a single second -
-   nothing guarantees that once we synced it, someone else didn't just
-   then make a modification. Such modifications wouldn't get noticed
-   until a new modification occured later.
-
-   Problem 2: Syncing cur/ directory is much more costly than syncing
-   new/. Moving mails from new/ to cur/ will always change mtime of
-   cur/ causing us to sync it as well.
-
-   Problem 3: We may not be able to move mail from new/ to cur/
-   because we're out of quota, or simply because we're accessing a
-   read-only mailbox.
-
-
-   MAILDIR_SYNC_SECS
-   -----------------
-
-   Several checks below use MAILDIR_SYNC_SECS, which should be maximum
-   clock drift between all computers accessing the maildir (eg. via
-   NFS), rounded up to next second. Our default is 1 second, since
-   everyone should be using NTP.
-
-   Note that setting it to 0 works only if there's only one computer
-   accessing the maildir. It's practically impossible to make two
-   clocks _exactly_ synchronized.
-
-   It might be possible to only use file server's clock by looking at
-   the atime field, but I don't know how well that would actually work.
-
-   cur directory
-   -------------
-
-   We have maildir_cur_dirty variable which is set to cur/ directory's
-   mtime when it's >= time() - MAILDIR_SYNC_SECS and we _think_ we have
-   synchronized the directory.
-
-   When maildir_cur_dirty is non-zero, we don't synchronize the cur/
-   directory until
-
-      a) cur/'s mtime changes
-      b) opening a mail fails with ENOENT
-      c) time() > maildir_cur_dirty + MAILDIR_SYNC_SECS
-
-   This allows us to modify the maildir multiple times without having
-   to sync it at every change. The sync will eventually be done to
-   make sure we didn't miss any external changes.
-
-   The maildir_cur_dirty is set when:
-
-      - we change message flags
-      - we expunge messages
-      - we move mail from new/ to cur/
-      - we sync cur/ directory and it's mtime is
-        >= time() - MAILDIR_SYNC_SECS
-
-   It's unset when we do the final syncing, ie. when mtime is
-   older than time() - MAILDIR_SYNC_SECS.
-
-   new directory
-   -------------
-
-   If new/'s mtime is >= time() - MAILDIR_SYNC_SECS, always synchronize
-   it. maildir_cur_dirty-like feature might save us a few syncs, but
-   that might break a client which saves a mail in one connection and
-   tries to fetch it in another one. new/ directory is almost always
-   empty, so syncing it should be very fast anyway. Actually this can
-   still happen if we sync only new/ dir while another client is also
-   moving mails from it to cur/ - it takes us a while to see them.
-   That's pretty unlikely to happen however, and only way to fix it
-   would be to always synchronize cur/ after new/.
-
-   Normally we move all mails from new/ to cur/ whenever we sync it. If
-   it's not possible for some reason, we set maildir_have_new flag on
-   which instructs synchronization to check files in new/ directory as
-   well. maildir_keep_new flag is also set which instructs syncing to
-   not even try to move mails to cur/ anymore.
-
-   If client tries to change a flag for message in new/, we try to
-   rename() it into cur/. If it's successful, we clear the
-   maildir_keep_new flag so at next sync we'll try to move all of them
-   to cur/. When all of them have been moved, maildir_have_new flag is
-   cleared as well. Expunges will also clear maildir_keep_new flag.
-
-   If rename() still fails because of ENOSPC or EDQUOT, we still save
-   the flag changes in index with dirty-flag on. When moving the mail
-   to cur/ directory, or when we notice it's already moved there, we
-   apply the flag changes to the filename, rename it and remove the
-   dirty flag. If there's dirty flags, this should be tried every time
-   after expunge or when closing the mailbox.
-
-   uidlist
-   -------
-
-   This file contains UID <-> filename mappings. It's updated only when
-   new mail arrives, so it may contain filenames that have already been
-   deleted. Updating is done by getting uidlist.lock file, writing the
-   whole uidlist into it and rename()ing it over the old uidlist. This
-   means there's no need to lock the file for reading.
-
-   Whenever uidlist is rewritten, it's mtime must be larger than the old
-   one's. Use utime() before rename() if needed.
-
-   Only time you have to read this file is when assigning new UIDs for
-   messages, to see if they already have UIDs. If file's mtime hasn't
-   changed, you don't have to do even that.
-
-   broken clients
-   --------------
-
-   Originally the middle identifier in Maildir filename was specified
-   only as <process id>_<delivery counter>. That however created a
-   problem with randomized PIDs which made it possible that the same
-   PID was reused within one second.
-
-   So if within one second a mail was delivered, MUA moved it to cur/
-   and another mail was delivered by a new process using same PID as
-   the first one, we likely ended up overwriting the first mail when
-   the second mail was moved over it.
-
-   Nowadays everyone should be giving a bit more specific identifier,
-   for example include microseconds in it which Dovecot does.
-
-   There's a simple way to prevent this from happening in some cases:
-   Don't move the mail from new/ to cur/ if it's mtime is >= time() -
-   MAILDIR_SYNC_SECS. The second delivery's link() call then fails
-   because the file is already in new/, and it will then use a
-   different filename. There's a few problems with this however:
-
-      - while it's usually possible to read the mtime from beginning of
-        the file name, it is against the Maildir specs. stat()ing the
-	file then makes syncing slower.
-      - another MUA might still move the mail to cur/
-      - if first file's flags are modified by either Dovecot or another
-        MUA, it's moved to cur/ (you _could_ just do the dirty-flagging
-	but that'd be ugly)
-
-   Because this is useful only for very few people and it requires some
-   extra code, I decided not to implement it at least for now.
-
-   It's also possible to never accidentally overwrite a mail by using
-   link() + unlink() rather than rename(). This however isn't very
-   good idea as it introduces potential race conditions when multiple
-   clients are accessing the mailbox:
-
-   Trying to move the same mail from new/ to cur/ at the same time:
-
-      a) Client 1 uses slightly different filename than client 2,
-         for example one sets read-flag on but the other doesn't.
-	 You have the same mail duplicated now.
-
-      b) Client 3 sees the mail between Client 1's and 2's link() calls
-         and changes it's flag. You have the same mail duplicated now.
-
-   And it gets worse when they're unlink()ing in cur/ directory:
-
-      c) Most other maildir clients use rename(). So if client 1 changes
-         mail's flag with link()+unlink() and client 2 using rename()
-	 changes it back between 1's link() and unlink(), the mail gets
-	 expunged.
-
-      d) If you try to deal with the duplicates by unlink()ing another
-         one of them, you might end up unlinking both of them.
-
-   So, what should we do then if we notice a duplicate? First of all,
-   it might not be a duplicate at all, readdir() might have just
-   returned it twice because it was just renamed. What we should do is
-   create a completely new base name for it and rename() it to that.
-   If the call fails with ENOENT, it only means that it wasn't a
-   duplicate after all.
-*/
-
-#include "lib.h"
-#include "buffer.h"
-#include "istream.h"
-#include "hash.h"
-#include "ioloop.h"
-#include "str.h"
-#include "maildir-index.h"
-#include "maildir-uidlist.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <utime.h>
-#include <sys/stat.h>
-
-#define MAILDIR_SYNC_SECS 1
-
-enum maildir_file_action {
-	MAILDIR_FILE_ACTION_EXPUNGE,
-        MAILDIR_FILE_ACTION_UPDATE_FLAGS,
-	MAILDIR_FILE_ACTION_NEW,
-	MAILDIR_FILE_ACTION_NONE,
-
-	MAILDIR_FILE_FLAG_NEWDIR	= 0x1000,
-	MAILDIR_FILE_FLAG_ALLOCED	= 0x2000,
-        MAILDIR_FILE_FLAGS		= 0x3000
-};
-
-struct maildir_hash_context {
-	struct mail_index *index;
-	struct mail_index_record *new_mail;
-
-	int failed;
-};
-
-struct maildir_hash_rec {
-	struct mail_index_record *rec;
-	enum maildir_file_action action;
-};
-#define ACTION(hash) ((hash)->action & ~MAILDIR_FILE_FLAGS)
-
-struct maildir_sync_context {
-        struct mail_index *index;
-	const char *new_dir, *cur_dir;
-
-	pool_t pool;
-	struct hash_table *files;
-	unsigned int new_count;
-
-	DIR *new_dirp;
-	struct dirent *new_dent;
-
-	struct maildir_uidlist *uidlist;
-        struct mail_cache_transaction_ctx *trans_ctx;
-	unsigned int readonly_check:1;
-	unsigned int flag_updates:1;
-	unsigned int uidlist_rewrite:1;
-	unsigned int new_mails_new:1;
-	unsigned int new_mails_cur:1;
-	unsigned int have_uncached_filenames:1;
-};
-
-static int maildir_sync_cur_dir(struct maildir_sync_context *ctx);
-
-/* a char* hash function from ASU -- from glib */
-static unsigned int maildir_hash(const void *p)
-{
-        const unsigned char *s = p;
-	unsigned int g, h = 0;
-
-	while (*s != ':' && *s != '\0') {
-		h = (h << 4) + *s;
-		if ((g = h & 0xf0000000UL)) {
-			h = h ^ (g >> 24);
-			h = h ^ g;
-		}
-		s++;
-	}
-
-	return h;
-}
-
-static int maildir_cmp(const void *p1, const void *p2)
-{
-	const char *s1 = p1, *s2 = p2;
-
-	while (*s1 == *s2 && *s1 != ':' && *s1 != '\0') {
-		s1++; s2++;
-	}
-	if ((*s1 == '\0' || *s1 == ':') &&
-	    (*s2 == '\0' || *s2 == ':'))
-		return 0;
-	return *s1 - *s2;
-}
-
-static int maildir_update_flags(struct maildir_sync_context *ctx,
-				struct mail_index_record *rec,
-				unsigned int seq, const char *new_fname)
-{
-	enum mail_flags flags;
-
-	if (ctx->index->lock_type != MAIL_LOCK_EXCLUSIVE)
-		return TRUE;
-
-	flags = maildir_filename_get_flags(new_fname, rec->msg_flags);
-	flags &= ~ctx->index->private_flags_mask;
-	flags |= rec->msg_flags & ctx->index->private_flags_mask;
-
-	if (flags != rec->msg_flags) {
-		if (!ctx->index->update_flags(ctx->index, rec,
-					      seq, MODIFY_REPLACE, flags, TRUE))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-static int maildir_sync_open_uidlist(struct maildir_sync_context *ctx)
-{
-	struct mail_index *index = ctx->index;
-	struct stat st;
-	const char *path;
-
-	if (ctx->uidlist != NULL)
-		return TRUE;
-
-	/* open it only if it's changed since we last synced it,
-	   or if we have uncached filenames. */
-	path = t_strconcat(index->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
-	if (stat(path, &st) < 0) {
-		if (errno == ENOENT) {
-			/* doesn't exist yet, create it */
-			switch (maildir_uidlist_try_lock(ctx->index)) {
-			case -1:
-				return FALSE;
-			case 1:
-				ctx->uidlist_rewrite = TRUE;
-				break;
-			}
-
-			return TRUE;
-		}
-		return index_file_set_syscall_error(index, path, "stat()");
-	}
-
-	/* FIXME: last_uidlist_mtime should be in index headers */
-	if (st.st_mtime == index->last_uidlist_mtime &&
-	    !ctx->have_uncached_filenames)
-		return TRUE;
-
-	ctx->uidlist = maildir_uidlist_open(index);
-	if (ctx->uidlist == NULL)
-		return TRUE;
-
-	if (ctx->uidlist->uid_validity != index->header->uid_validity) {
-		/* uidvalidity changed */
-		if (!index->rebuilding && index->opened) {
-			index_set_corrupted(index,
-					    "UIDVALIDITY changed in uidlist");
-			return FALSE;
-		}
-
-		index->header->uid_validity = ctx->uidlist->uid_validity;
-		i_assert(index->header->next_uid == 1);
-	}
-
-	if (index->header->next_uid > ctx->uidlist->next_uid) {
-		index_set_corrupted(index, "index.next_uid (%u) > "
-				    "uidlist.next_uid (%u)",
-				    index->header->next_uid,
-				    ctx->uidlist->next_uid);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static int maildir_time_cmp(const void *p1, const void *p2)
-{
-	const char *s1 = *((const char **) p1);
-	const char *s2 = *((const char **) p2);
-	time_t t1 = 0, t2 = 0;
-
-	/* we have to do numeric comparision, strcmp() will break when
-	   there's different amount of digits (mostly the 999999999 ->
-	   1000000000 change in Sep 9 2001) */
-	while (*s1 >= '0' && *s1 <= '9') {
-		t1 = t1*10 + (*s1 - '0');
-		s1++;
-	}
-	while (*s2 >= '0' && *s2 <= '9') {
-		t2 = t2*10 + (*s2 - '0');
-		s2++;
-	}
-
-	return t1 < t2 ? -1 : t1 > t2 ? 1 : 0;
-}
-
-static int maildir_full_sync_finish_new_mails(struct maildir_sync_context *ctx)
-{
-	struct hash_iterate_context *iter;
-	void *key, *value;
-	const char *dir, **new_files;
-	buffer_t *buf;
-	unsigned int i;
-	int new_dir;
-
-	ctx->uidlist_rewrite = TRUE;
-
-	/* then there's the completely new mails. sort them by the filename
-	   so we should get them to same order as they were created. */
-	buf = buffer_create_static_hard(ctx->pool,
-					ctx->new_count * sizeof(const char *));
-	iter = hash_iterate_init(ctx->files);
-	while (hash_iterate(iter, &key, &value)) {
-		struct maildir_hash_rec *hash_rec = value;
-
-		if (ACTION(hash_rec) == MAILDIR_FILE_ACTION_NEW) {
-			buffer_append(buf, (const void *) &key,
-				      sizeof(const char *));
-		}
-	}
-	hash_iterate_deinit(iter);
-	i_assert(buffer_get_used_size(buf) ==
-		 ctx->new_count * sizeof(const char *));
-
-	new_files = buffer_get_modifyable_data(buf, NULL);
-	qsort(new_files, ctx->new_count, sizeof(const char *),
-	      maildir_time_cmp);
-
-	if (!ctx->index->maildir_keep_new) {
-		dir = ctx->cur_dir;
-		new_dir = FALSE;
-	} else {
-		/* this is actually slightly wrong, because we don't really
-		   know if some of the new messages are in cur/ already.
-		   we could know that by saving it into buffer, but that'd
-		   require extra memory. luckily it doesn't really matter if
-		   we say it's in new/, but it's actually in cur/. we have
-		   to deal with such case anyway since another client might
-		   have just moved it. */
-		dir = ctx->new_dir;
-		new_dir = TRUE;
-		ctx->index->maildir_have_new = TRUE;
-	}
-
-	for (i = 0; i < ctx->new_count; i++) {
-		if (!maildir_index_append_file(&ctx->trans_ctx, ctx->index,
-					       new_files[i], new_dir))
-			return FALSE;
-	}
-	ctx->new_count = 0;
-
-	return TRUE;
-}
-
-static int maildir_full_sync_finish(struct maildir_sync_context *ctx)
-{
-	struct mail_index *index = ctx->index;
-        struct maildir_uidlist *uidlist;
-	struct mail_index_record *rec, *first_rec, *last_rec;
-	struct maildir_hash_rec *hash_rec;
-	struct maildir_uidlist_rec uid_rec;
-        enum maildir_file_action action;
-	const char *fname, *dir;
-	void *orig_key, *orig_value;
-	unsigned int seq, first_seq, last_seq, uid, last_uid, new_flag;
-	int new_dir, skip_next;
-
-	if (ctx->new_count > 0) {
-		/* new mails, either they're already in uidlist or we have
-		   to add them there. If we want to add them, we'll need to
-		   sync it locked. */
-		if (maildir_uidlist_try_lock(ctx->index) < 0)
-			return FALSE;
-
-		if (!maildir_sync_open_uidlist(ctx))
-			return FALSE;
-	}
-
-        seq = 1;
-	rec = index->lookup(index, 1);
-	uidlist = ctx->uidlist;
-
-	if (uidlist == NULL)
-		memset(&uid_rec, 0, sizeof(uid_rec));
-	else {
-		if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
-			return FALSE;
-	}
-
-	first_rec = last_rec = NULL;
-	first_seq = last_seq = 0;
-	skip_next = FALSE;
-	while (rec != NULL) {
-		uid = rec->uid;
-
-		/* skip over the expunged records in uidlist */
-		while (uid_rec.uid != 0 && uid_rec.uid < uid) {
-			if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
-				return FALSE;
-		}
-
-		fname = maildir_get_location(index, rec, NULL);
-		if (fname == NULL) {
-			/* filename not cached, it must be in uidlist or
-			   it's expunged */
-			fname = uid_rec.uid == rec->uid ?
-				uid_rec.filename : NULL;
-		}
-
-		if (fname == NULL) {
-			hash_rec = NULL;
-			action = MAILDIR_FILE_ACTION_EXPUNGE;
-		} else if (hash_lookup_full(ctx->files, fname,
-					    &orig_key, &orig_value)) {
-			hash_rec = orig_value;
-			action = ACTION(hash_rec);
-		} else {
-			/* none action */
-			hash_rec = NULL;
-			action = MAILDIR_FILE_ACTION_NONE;
-		}
-
-		if (uid_rec.uid == uid &&
-		    maildir_cmp(fname, uid_rec.filename) != 0) {
-			index_set_corrupted(index,
-				"Filename mismatch for UID %u: %s vs %s",
-				uid, fname, uid_rec.filename);
-			return FALSE;
-		}
-
-		if (uid_rec.uid > uid && hash_rec != NULL &&
-		    (action == MAILDIR_FILE_ACTION_UPDATE_FLAGS ||
-		     action == MAILDIR_FILE_ACTION_NONE)) {
-			/* it's UID has changed. shouldn't happen. */
-			index_set_corrupted(index,
-					    "UID changed for %s/%s: %u -> %u",
-					    index->mailbox_path, fname,
-					    uid, uid_rec.uid);
-			return FALSE;
-		}
-
-		switch (action) {
-		case MAILDIR_FILE_ACTION_EXPUNGE:
-			if (first_rec == NULL) {
-				first_rec = rec;
-				first_seq = seq;
-			}
-			last_rec = rec;
-			last_seq = seq;
-			break;
-		case MAILDIR_FILE_ACTION_NEW:
-			/* filename wasn't cached */
-			new_flag = hash_rec->action & MAILDIR_FILE_FLAG_NEWDIR;
-			hash_rec->action = MAILDIR_FILE_ACTION_NONE | new_flag;
-			ctx->new_count--;
-
-			if (!maildir_cache_update_file(&ctx->trans_ctx, index,
-						       rec, fname, new_flag))
-				return FALSE;
-			/* fall through */
-		case MAILDIR_FILE_ACTION_UPDATE_FLAGS:
-			new_dir = (hash_rec->action &
-				   MAILDIR_FILE_FLAG_NEWDIR) != 0;
-			maildir_index_update_filename(index, rec->uid,
-						      orig_key, new_dir);
-			if (!maildir_update_flags(ctx, rec, seq, orig_key))
-				return FALSE;
-			/* fall through */
-		case MAILDIR_FILE_ACTION_NONE:
-			if (first_rec != NULL) {
-				if (!index->expunge(index, first_rec, last_rec,
-						    first_seq, last_seq, TRUE))
-					return FALSE;
-				first_rec = NULL;
-
-				seq = first_seq;
-				rec = index->lookup(index, seq);
-				skip_next = TRUE;
-			}
-			break;
-		default:
-			i_unreached();
-		}
-
-		if (uid_rec.uid == uid) {
-			if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
-				return FALSE;
-		}
-
-		if (skip_next)
-			skip_next = FALSE;
-		else {
-			rec = index->next(index, rec);
-			seq++;
-		}
-	}
-
-	if (first_rec != NULL) {
-		if (!index->expunge(index, first_rec, last_rec,
-				    first_seq, last_seq, TRUE))
-			return FALSE;
-		seq = first_seq;
-	}
-
-	if (seq-1 != index->header->messages_count) {
-		index_set_corrupted(index,
-				    "Wrong messages_count in header (%u != %u)",
-				    seq, index->header->messages_count);
-		return FALSE;
-	}
-
-	/* if there's new mails which are already in uidlist, get them */
-	last_uid = 0;
-	while (uid_rec.uid != 0) {
-		if (hash_lookup_full(ctx->files, uid_rec.filename,
-				     &orig_key, &orig_value))
-			hash_rec = orig_value;
-		else
-			hash_rec = NULL;
-
-		if (hash_rec != NULL &&
-		    ACTION(hash_rec) == MAILDIR_FILE_ACTION_NONE) {
-			/* it's a duplicate, shouldn't happen */
-			i_error("%s: Found duplicate filename %s, rebuilding",
-				ctx->uidlist->fname, uid_rec.filename);
-			(void)unlink(ctx->uidlist->fname);
-
-			if (INDEX_IS_UIDLIST_LOCKED(index))
-				ctx->uidlist_rewrite = TRUE;
-			hash_rec = NULL;
-		}
-
-		if (hash_rec != NULL) {
- 			i_assert(ACTION(hash_rec) == MAILDIR_FILE_ACTION_NEW);
-
-			/* make sure we set the same UID for it. */
-			if (index->header->next_uid > uid_rec.uid) {
-				index_set_corrupted(index,
-						    "index.next_uid (%u) > "
-						    "uid_rec.uid (%u)",
-						    index->header->next_uid,
-						    uid_rec.uid);
-				return FALSE;
-			}
-			index->header->next_uid = uid_rec.uid;
-
-			new_flag = hash_rec->action & MAILDIR_FILE_FLAG_NEWDIR;
-			hash_rec->action = MAILDIR_FILE_ACTION_NONE | new_flag;
-			ctx->new_count--;
-
-			if (new_flag != 0)
-				ctx->index->maildir_have_new = TRUE;
-			dir = new_flag != 0 ? ctx->new_dir : ctx->cur_dir;
-
-			if (!maildir_index_append_file(&ctx->trans_ctx, index,
-						       orig_key, new_flag != 0))
-				return FALSE;
-		}
-
-		if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
-			return FALSE;
-	}
-
-	if (ctx->uidlist != NULL) {
-		/* update our next_uid. it should have been checked for
-		   sanity already. */
-		struct stat st;
-
-		i_assert(index->header->next_uid <= ctx->uidlist->next_uid);
-                index->header->next_uid = ctx->uidlist->next_uid;
-
-		/* uidlist is now synced, remember that. */
-		if (fstat(i_stream_get_fd(ctx->uidlist->input), &st) < 0) {
-			return index_file_set_syscall_error(index,
-							    ctx->uidlist->fname,
-							    "fstat()");
-		}
-		index->last_uidlist_mtime = st.st_mtime;
-	}
-
-	if (ctx->new_count > 0 && INDEX_IS_UIDLIST_LOCKED(index))
-                maildir_full_sync_finish_new_mails(ctx);
-
-	/* all done (or can't do it since we don't have lock) */
-	ctx->index->maildir_synced_once = TRUE;
-	if (ctx->trans_ctx != NULL)
-		mail_cache_transaction_commit(ctx->trans_ctx);
-	return TRUE;
-}
-
-static int maildir_full_sync_init(struct maildir_sync_context *ctx,
-				  int only_new)
-{
-	struct mail_index *index = ctx->index;
-	struct mail_index_record *rec;
-	struct maildir_hash_rec *hash_rec;
-	const char *fname;
-	size_t size;
-	int new_dir, have_new;
-
-	if (index->header->messages_count >= INT_MAX/32) {
-		index_set_corrupted(index, "Header says %u messages",
-				    index->header->messages_count);
-		return FALSE;
-	}
-
-	/* we're resyncing everything, so reset the filename hash */
-	if (index->new_filenames != NULL) {
-		hash_destroy(index->new_filenames);
-		index->new_filenames = NULL;
-	}
-
-	if (index->new_filename_pool != NULL)
-		p_clear(index->new_filename_pool);
-
-	/* reset synced-flag too, just in case something fails and we don't
-	   have up-to-date new_filenames */
-	ctx->index->maildir_synced_once = FALSE;
-
-	/* read current messages in index into hash */
-	size = nearest_power(index->header->messages_count *
-			     sizeof(struct maildir_hash_rec) + 1024);
-	ctx->pool = pool_alloconly_create("maildir sync", I_MAX(size, 16384));
-	ctx->files = hash_create(default_pool, ctx->pool,
-				 index->header->messages_count * 2,
-				 maildir_hash, maildir_cmp);
-	ctx->new_count = 0;
-
-	have_new = FALSE;
-
-	/* Now we'll fill the hash with cached filenames. This is done mostly
-	   just to save some memory since we can use pointers to mmaped cache
-	   file. Note that all records may not have the filename cached.
-
-	   WARNING: Cache file must not be modified as long as these pointers
-	   exist, as modifying might change the mmap base address. The call
-	   below makes sure that cache file is initially fully mmaped. */
-	if (mail_cache_get_mmaped(index->cache, &size) == NULL)
-		return FALSE;
-
-	rec = index->lookup(index, 1);
-	while (rec != NULL) {
-		fname = maildir_get_location(index, rec, &new_dir);
-		if (fname == NULL)
-                        ctx->have_uncached_filenames = TRUE;
-
-		if (new_dir)
-			have_new = TRUE;
-
-		if ((!only_new || new_dir) && fname != NULL) {
-			hash_rec = p_new(ctx->pool, struct maildir_hash_rec, 1);
-			hash_rec->rec = rec;
-			hash_rec->action = MAILDIR_FILE_ACTION_EXPUNGE;
-
-			if (hash_lookup(ctx->files, fname) != NULL) {
-				index_set_corrupted(index,
-					"Duplicated message %s", fname);
-				return FALSE;
-			}
-
-			hash_insert(ctx->files, (void *) fname, hash_rec);
-		}
-
-		rec = index->next(index, rec);
-	}
-
-	index->maildir_have_new = have_new;
-	return TRUE;
-}
-
-static int maildir_fix_duplicate(struct mail_index *index,
-				 const char *old_fname, int new_dir)
-{
-	const char *new_fname, *old_path, *new_path;
-	int ret = TRUE;
-
-	t_push();
-
-	old_path = t_strconcat(index->mailbox_path, new_dir ? "/new/" : "/cur/",
-			       old_fname, NULL);
-
-	new_fname = maildir_generate_tmp_filename(&ioloop_timeval);
-	new_path = t_strconcat(index->mailbox_path, "/new/", new_fname, NULL);
-
-	if (rename(old_path, new_path) == 0) {
-		i_warning("Fixed duplicate in %s: %s -> %s",
-			  index->mailbox_path, old_fname, new_fname);
-	} else if (errno != ENOENT) {
-		index_set_error(index, "rename(%s, %s) failed: %m",
-				old_path, new_path);
-		ret = FALSE;
-	}
-	t_pop();
-
-	return ret;
-}
-
-static int maildir_full_sync_dir(struct maildir_sync_context *ctx,
-				 int new_dir, DIR *dirp, struct dirent *d)
-{
-	struct hash_iterate_context *iter;
-	void *key, *value;
-	struct maildir_hash_rec *hash_rec;
-	void *orig_key, *orig_value;
-	int newflag;
-
-	newflag = new_dir ? MAILDIR_FILE_FLAG_NEWDIR : 0;
-
-	do {
-		if (d->d_name[0] == '.')
-			continue;
-
-		if (!hash_lookup_full(ctx->files, d->d_name,
-				      &orig_key, &orig_value)) {
-			hash_rec = p_new(ctx->pool, struct maildir_hash_rec, 1);
-		} else {
-			hash_rec = orig_value;
-			if (ACTION(hash_rec) != MAILDIR_FILE_ACTION_EXPUNGE) {
-				if (!maildir_fix_duplicate(ctx->index,
-							   d->d_name, new_dir))
-					return FALSE;
-				continue;
-			}
-		}
-
-		if (hash_rec->rec == NULL) {
-			/* new message */
-			if (ctx->readonly_check &&
-			    !ctx->have_uncached_filenames)
-				continue;
-
-			if (new_dir)
-				ctx->new_mails_new = TRUE;
-			else
-				ctx->new_mails_cur = TRUE;
-
-			ctx->new_count++;
-			hash_rec->action = MAILDIR_FILE_ACTION_NEW | newflag;
-			hash_insert(ctx->files, p_strdup(ctx->pool, d->d_name),
-				    hash_rec);
-			continue;
-		}
-
-		if (strcmp(orig_key, d->d_name) != 0) {
-			hash_rec->action =
-				MAILDIR_FILE_ACTION_UPDATE_FLAGS | newflag;
-
-			hash_insert(ctx->files, p_strdup(ctx->pool, d->d_name),
-				    hash_rec);
-                        ctx->flag_updates = TRUE;
-		} else {
-			hash_rec->action = MAILDIR_FILE_ACTION_NONE | newflag;
-		}
-	} while ((d = readdir(dirp)) != NULL);
-
-	/* records that are left to hash must not have any (filename) pointers
-	   to cache file. So remove none actions, and p_strdup() expunge
-	   actions. */
-	iter = hash_iterate_init(ctx->files);
-	while (hash_iterate(iter, &key, &value)) {
-		struct maildir_hash_rec *hash_rec = value;
-
-		switch (ACTION(hash_rec)) {
-		case MAILDIR_FILE_ACTION_NONE:
-			hash_remove(ctx->files, key);
-			break;
-		case MAILDIR_FILE_ACTION_EXPUNGE:
-			if (hash_rec->action & MAILDIR_FILE_FLAG_ALLOCED) {
-				/* we're getting here because our recently
-				   inserted node is traversed as well */
-				break;
-			}
-
-			hash_rec->action |= MAILDIR_FILE_FLAG_ALLOCED;
-			hash_insert(ctx->files,
-				    p_strdup(ctx->pool, key), value);
-			break;
-		default:
-			break;
-		}
-	}
-	hash_iterate_deinit(iter);
-
-	return TRUE;
-}
-
-static int maildir_new_scan_first_file(struct maildir_sync_context *ctx)
-{
-	DIR *dirp;
-	struct dirent *d;
-
-	dirp = opendir(ctx->new_dir);
-	if (dirp == NULL) {
-		return index_file_set_syscall_error(ctx->index, ctx->new_dir,
-						    "opendir()");
-	}
-
-	/* find first file */
-	while ((d = readdir(dirp)) != NULL) {
-		if (d->d_name[0] != '.')
-			break;
-	}
-
-	if (d == NULL) {
-		if (closedir(dirp) < 0) {
-			index_file_set_syscall_error(ctx->index, ctx->new_dir,
-						     "closedir()");
-		}
-	} else {
-		ctx->new_dirp = dirp;
-		ctx->new_dent = d;
-	}
-
-	return TRUE;
-}
-
-static int maildir_full_sync_dirs(struct maildir_sync_context *ctx)
-{
-	DIR *dirp;
-	int failed;
-
-	if (ctx->new_dirp == NULL &&
-	    (ctx->index->maildir_have_new || ctx->index->maildir_keep_new)) {
-		if (!maildir_new_scan_first_file(ctx))
-			return FALSE;
-	}
-
-	if (ctx->new_dent != NULL) {
-		if (!maildir_full_sync_dir(ctx, TRUE, ctx->new_dirp,
-					   ctx->new_dent))
-			return FALSE;
-                ctx->new_dent = NULL;
-	}
-
-	dirp = opendir(ctx->cur_dir);
-	if (dirp == NULL) {
-		return index_file_set_syscall_error(ctx->index, ctx->cur_dir,
-						    "opendir()");
-	}
-
-	failed = !maildir_full_sync_dir(ctx, FALSE, dirp, readdir(dirp));
-
-	if (closedir(dirp) < 0) {
-		return index_file_set_syscall_error(ctx->index, ctx->cur_dir,
-						    "closedir()");
-	}
-
-	return !failed;
-}
-
-static int maildir_sync_new_dir_full(struct maildir_sync_context *ctx)
-{
-	if (!ctx->index->set_lock(ctx->index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	if (!maildir_full_sync_init(ctx, TRUE))
-		return FALSE;
-
-	if (!maildir_full_sync_dir(ctx, TRUE, ctx->new_dirp, ctx->new_dent))
-		return FALSE;
-	ctx->new_dent = NULL;
-
-	if (!maildir_full_sync_finish(ctx))
-		return FALSE;
-
-	return TRUE;
-}
-
-static int maildir_sync_new_dir(struct maildir_sync_context *ctx,
-				int move_to_cur, int append_index)
-{
-	struct dirent *d;
-	string_t *sourcepath, *destpath;
-	const char *final_dir;
-
-	if (append_index) {
-		if (ctx->index->maildir_have_new) {
-			/* some of the mails in new/ are already indexed.
-			   we'll have to do a full sync. */
-			return maildir_sync_new_dir_full(ctx);
-		}
-
-		if (!ctx->index->set_lock(ctx->index, MAIL_LOCK_EXCLUSIVE))
-			return FALSE;
-
-		switch (maildir_uidlist_try_lock(ctx->index)) {
-		case -1:
-			return FALSE;
-		case 0:
-			/* couldn't get a lock.
-			   no point in doing more. */
-			return TRUE;
-		}
-
-		/* make sure uidlist is up to date.
-		   if it's not, do a full sync. */
-		if (!maildir_sync_open_uidlist(ctx))
-			return FALSE;
-
-		if (ctx->uidlist != NULL)
-			return maildir_sync_cur_dir(ctx);
-
-		ctx->uidlist_rewrite = TRUE;
-	}
-
-	d = ctx->new_dent;
-	ctx->new_dent = NULL;
-
-	sourcepath = t_str_new(PATH_MAX);
-	destpath = t_str_new(PATH_MAX);
-
-	final_dir = move_to_cur ? ctx->cur_dir : ctx->new_dir;
-
-	do {
-		if (d->d_name[0] == '.')
-			continue;
-
-		str_truncate(sourcepath, 0);
-		str_printfa(sourcepath, "%s/%s", ctx->new_dir, d->d_name);
-
-		if (move_to_cur) {
-			str_truncate(destpath, 0);
-			str_printfa(destpath, "%s/%s", ctx->cur_dir, d->d_name);
-
-			if (rename(str_c(sourcepath), str_c(destpath)) < 0 &&
-			    errno != ENOENT) {
-				if (ENOSPACE(errno))
-					ctx->index->nodiskspace = TRUE;
-				else if (errno == EACCES)
-					ctx->index->mailbox_readonly = TRUE;
-				else {
-					index_set_error(ctx->index,
-						"rename(%s, %s) failed: %m",
-						str_c(sourcepath),
-						str_c(destpath));
-					return FALSE;
-				}
-
-				ctx->index->maildir_keep_new = TRUE;
-				if (!append_index) {
-					ctx->new_dent = d;
-					return TRUE;
-				}
-
-				/* continue by keeping them in new/ dir */
-				final_dir = ctx->new_dir;
-				move_to_cur = FALSE;
-			}
-		}
-
-		if (append_index) {
-			if (!move_to_cur)
-				ctx->index->maildir_have_new = TRUE;
-
-			t_push();
-			if (!maildir_index_append_file(&ctx->trans_ctx,
-						       ctx->index, d->d_name,
-						       !move_to_cur)) {
-				t_pop();
-				return FALSE;
-			}
-			t_pop();
-		}
-	} while ((d = readdir(ctx->new_dirp)) != NULL);
-
-	return TRUE;
-}
-
-static int maildir_sync_cur_dir(struct maildir_sync_context *ctx)
-{
-	struct mail_index *index = ctx->index;
-
-	if (ctx->new_dent != NULL && !index->maildir_keep_new) {
-		/* there's also new mails. move them into cur/ first, if we
-		   can lock the uidlist */
-		switch (maildir_uidlist_try_lock(index)) {
-		case -1:
-			return FALSE;
-		case 1:
-			if (!maildir_sync_new_dir(ctx, TRUE, FALSE))
-				return FALSE;
-		}
-	}
-
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	if (!maildir_full_sync_init(ctx, FALSE) ||
-	    !maildir_full_sync_dirs(ctx) ||
-	    !maildir_full_sync_finish(ctx))
-		return FALSE;
-
-	return TRUE;
-}
-
-static int maildir_index_sync_context(struct maildir_sync_context *ctx,
-				      int *changes)
-
-{
-        struct mail_index *index = ctx->index;
-	struct stat st;
-	time_t new_mtime, cur_mtime;
-
-	if (!maildir_try_flush_dirty_flags(ctx->index, FALSE))
-		return FALSE;
-
-	if (stat(ctx->new_dir, &st) < 0) {
-		index_file_set_syscall_error(index, ctx->new_dir, "stat()");
-		return FALSE;
-	}
-	new_mtime = st.st_mtime;
-
-	if (stat(ctx->cur_dir, &st) < 0) {
-		index_file_set_syscall_error(index, ctx->cur_dir, "stat()");
-		return FALSE;
-	}
-	cur_mtime = st.st_mtime;
-
-	if (new_mtime != index->last_new_mtime ||
-	    new_mtime >= ioloop_time - MAILDIR_SYNC_SECS) {
-		if (!maildir_new_scan_first_file(ctx))
-			return FALSE;
-	}
-
-	if (cur_mtime != index->sync_stamp &&
-	    index->sync_dirty_stamp == 0) {
-		/* update index->sync_stamp from header.
-		   set_lock() does it automatically. */
-		if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-			return FALSE;
-	}
-
-	if (cur_mtime != index->sync_stamp ||
-	    (index->sync_dirty_stamp != 0 &&
-	     index->sync_dirty_stamp < ioloop_time - MAILDIR_SYNC_SECS)) {
-		/* cur/ changed, or delayed cur/ check */
-		if (changes != NULL)
-			*changes = TRUE;
-
-		if (!maildir_sync_cur_dir(ctx))
-			return FALSE;
-	}
-
-	if (ctx->new_dent != NULL) {
-		if (changes != NULL)
-			*changes = TRUE;
-
-		if (!maildir_sync_new_dir(ctx, !index->maildir_keep_new, TRUE))
-			return FALSE;
-
-		/* this will set maildir_cur_dirty. it may actually be
-		   different from cur/'s mtime if we're unlucky, but that only
-		   causes extra sync and it's not worth the extra stat() */
-		if (ctx->new_dent == NULL &&
-		    (ctx->new_count == 0 || !ctx->new_mails_new))
-			cur_mtime = time(NULL);
-	}
-
-	if (ctx->uidlist_rewrite) {
-		i_assert(INDEX_IS_UIDLIST_LOCKED(index));
-
-		if (!maildir_uidlist_rewrite(index, &index->last_uidlist_mtime))
-			return FALSE;
-	}
-
-	if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
-		if (index->maildir_have_new)
-			index->header->flags |= MAIL_INDEX_FLAG_MAILDIR_NEW;
-		else
-			index->header->flags &= ~MAIL_INDEX_FLAG_MAILDIR_NEW;
-	}
-
-	if (index->sync_dirty_stamp == 0 ||
-	    index->sync_dirty_stamp < ioloop_time - MAILDIR_SYNC_SECS) {
-		if (cur_mtime >= ioloop_time - MAILDIR_SYNC_SECS)
-			index->sync_dirty_stamp = cur_mtime;
-		else if (ctx->new_count == 0 || !ctx->new_mails_cur)
-			index->sync_dirty_stamp = 0;
-		else {
-			/* uidlist is locked, wait for a while before
-			   trying again */
-			index->sync_dirty_stamp = ioloop_time;
-		}
-	}
-
-	index->sync_stamp = cur_mtime;
-	if (ctx->new_dent == NULL &&
-	    (ctx->new_count == 0 || !ctx->new_mails_new))
-		index->last_new_mtime = new_mtime;
-
-	return TRUE;
-}
-
-static int maildir_full_sync_finish_readonly(struct maildir_sync_context *ctx)
-{
-	struct mail_index *index = ctx->index;
-	struct mail_index_record *rec;
-	struct maildir_hash_rec *hash_rec;
-	struct maildir_uidlist *uidlist;
-	struct maildir_uidlist_rec uid_rec;
-	void *orig_key, *orig_value;
-	const char *fname;
-	unsigned int seq;
-	int new_dir, tried_uidlist;
-
-	if (!ctx->flag_updates && !ctx->have_uncached_filenames) {
-		ctx->index->maildir_synced_once = TRUE;
-		return TRUE;
-	}
-
-	memset(&uid_rec, 0, sizeof(uid_rec));
-	uidlist = ctx->uidlist;
-	tried_uidlist = FALSE;
-
-	rec = index->lookup(index, 1); seq = 1;
-	for (; rec != NULL; rec = index->next(index, rec), seq++) {
-		fname = maildir_get_location(index, rec, NULL);
-		if (fname == NULL) {
-			/* not cached, get it from uidlist */
-			if (uidlist == NULL && !tried_uidlist) {
-				ctx->have_uncached_filenames = TRUE;
-				if (!maildir_sync_open_uidlist(ctx))
-					return FALSE;
-
-				uidlist = ctx->uidlist;
-				tried_uidlist = TRUE;
-
-				/* get the initial record */
-				if (uidlist != NULL &&
-				    maildir_uidlist_next(uidlist, &uid_rec) < 0)
-					return FALSE;
-			}
-
-			if (uidlist == NULL) {
-				/* uidlist doesn't exist? shouldn't happen */
-				continue;
-			}
-
-			while (uid_rec.uid != 0 && uid_rec.uid < rec->uid) {
-				if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
-					return FALSE;
-			}
-
-			if (uid_rec.uid != rec->uid) {
-				/* not in uidlist, it's expunged */
-				continue;
-			}
-
-			fname = uid_rec.filename;
-		}
-
-		if (!hash_lookup_full(ctx->files, fname,
-				      &orig_key, &orig_value))
-			continue;
-
-		hash_rec = orig_value;
-		if (ACTION(hash_rec) != MAILDIR_FILE_ACTION_UPDATE_FLAGS &&
-		    ACTION(hash_rec) != MAILDIR_FILE_ACTION_NEW)
-			continue;
-
-		new_dir = (hash_rec->action & MAILDIR_FILE_FLAG_NEWDIR) != 0;
-		maildir_index_update_filename(index, rec->uid,
-					      orig_key, new_dir);
-
-		if (!maildir_update_flags(ctx, rec, seq, orig_key))
-			return FALSE;
-	}
-
-	ctx->index->maildir_synced_once = TRUE;
-	return TRUE;
-}
-
-static int maildir_index_sync_context_readonly(struct maildir_sync_context *ctx)
-{
-	struct mail_index *index = ctx->index;
-	struct stat st;
-	int cur_changed;
-
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-
-	if (!index->maildir_synced_once) {
-		/* we haven't synced yet in this session. do it */
-		cur_changed = TRUE;
-	} else {
-		if (stat(ctx->cur_dir, &st) < 0) {
-			index_file_set_syscall_error(index, ctx->cur_dir,
-						     "stat()");
-			return FALSE;
-		}
-
-		cur_changed = st.st_mtime != index->sync_stamp ||
-			index->sync_dirty_stamp != 0;
-	}
-
-	if (!cur_changed) {
-		if (!index->maildir_have_new) {
-			/* no changes */
-			return TRUE;
-		}
-
-		if (stat(ctx->new_dir, &st) < 0) {
-			return index_file_set_syscall_error(index, ctx->new_dir,
-							    "stat()");
-		}
-		if (st.st_mtime == index->last_new_mtime &&
-		    st.st_mtime < ioloop_time - MAILDIR_SYNC_SECS) {
-			/* no changes */
-			return TRUE;
-		}
-
-		if (!maildir_new_scan_first_file(ctx))
-			return FALSE;
-	}
-
-	/* ok, something's changed. check only changes in file names. */
-
-	/* if we can get exclusive lock, we can update the index
-	   directly. but don't rely on it. */
-	(void)index->try_lock(index, MAIL_LOCK_EXCLUSIVE);
-
-	if (!maildir_full_sync_init(ctx, FALSE) ||
-	    !maildir_full_sync_dirs(ctx) ||
-	    !maildir_full_sync_finish_readonly(ctx))
-		return FALSE;
-
-	return TRUE;
-}
-
-static void maildir_index_sync_deinit(struct maildir_sync_context *ctx)
-{
-	// FIXME: remove new flags from cache if needed
-	if (ctx->trans_ctx != NULL)
-                mail_cache_transaction_end(ctx->trans_ctx);
-	if (ctx->uidlist != NULL)
-		maildir_uidlist_close(ctx->uidlist);
-	if (ctx->files != NULL)
-		hash_destroy(ctx->files);
-	if (ctx->pool != NULL)
-		pool_unref(ctx->pool);
-
-	if (ctx->new_dirp != NULL) {
-		if (closedir(ctx->new_dirp) < 0) {
-			index_file_set_syscall_error(ctx->index, ctx->new_dir,
-						     "closedir()");
-		}
-	}
-
-	maildir_uidlist_unlock(ctx->index);
-}
-
-static struct maildir_sync_context *
-maildir_sync_context_new(struct mail_index *index)
-{
-        struct maildir_sync_context *ctx;
-
-	ctx = t_new(struct maildir_sync_context, 1);
-	ctx->index = index;
-	ctx->new_dir = t_strconcat(index->mailbox_path, "/new", NULL);
-	ctx->cur_dir = t_strconcat(index->mailbox_path, "/cur", NULL);
-	return ctx;
-}
-
-int maildir_index_sync_readonly(struct mail_index *index,
-				const char *fname, int *found)
-{
-        struct maildir_sync_context *ctx;
-	struct maildir_hash_rec *hash_rec;
-	int ret;
-
-	ctx = maildir_sync_context_new(index);
-	ctx->readonly_check = TRUE;
-
-	ret = maildir_index_sync_context_readonly(ctx);
-
-	if (!ret || ctx->files == NULL || fname == NULL)
-		*found = FALSE;
-	else {
-		hash_rec = hash_lookup(ctx->files, fname);
-		*found = hash_rec != NULL &&
-			hash_rec->action != MAILDIR_FILE_ACTION_EXPUNGE;
-	}
-	maildir_index_sync_deinit(ctx);
-	return ret;
-}
-
-int maildir_index_sync(struct mail_index *index, int minimal_sync,
-		       enum mail_lock_type data_lock_type __attr_unused__,
-		       int *changes)
-{
-        struct maildir_sync_context *ctx;
-	int ret;
-
-	i_assert(index->lock_type != MAIL_LOCK_SHARED);
-
-	if (changes != NULL)
-		*changes = FALSE;
-
-	if (minimal_sync)
-		return TRUE;
-
-	ctx = maildir_sync_context_new(index);
-	ret = maildir_index_sync_context(ctx, changes);
-        maildir_index_sync_deinit(ctx);
-	return ret;
-}
--- a/src/lib-index/maildir/maildir-uidlist.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,243 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "istream.h"
-#include "str.h"
-#include "write-full.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "maildir-index.h"
-#include "maildir-uidlist.h"
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <utime.h>
-
-/* how many seconds to wait before overriding uidlist.lock */
-#define UIDLIST_LOCK_STALE_TIMEOUT (60*5)
-
-int maildir_uidlist_try_lock(struct mail_index *index)
-{
-	const char *path;
-	mode_t old_mask;
-	int fd;
-
-	if (INDEX_IS_UIDLIST_LOCKED(index))
-		return 1;
-
-	path = t_strconcat(index->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
-        old_mask = umask(0777 & ~index->mail_create_mode);
-	fd = file_dotlock_open(path, NULL, 0, 0, UIDLIST_LOCK_STALE_TIMEOUT,
-			       NULL, NULL);
-	umask(old_mask);
-	if (fd == -1) {
-		if (errno == EAGAIN)
-			return 0;
-		return -1;
-	}
-
-	index->maildir_lock_fd = fd;
-	return 1;
-}
-
-void maildir_uidlist_unlock(struct mail_index *index)
-{
-	const char *path;
-
-	if (!INDEX_IS_UIDLIST_LOCKED(index))
-		return;
-
-	path = t_strconcat(index->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
-	(void)file_dotlock_delete(path, index->maildir_lock_fd);
-	index->maildir_lock_fd = -1;
-}
-
-struct maildir_uidlist *maildir_uidlist_open(struct mail_index *index)
-{
-	const char *path, *line;
-	struct maildir_uidlist *uidlist;
-	unsigned int version;
-	int fd;
-
-	path = t_strconcat(index->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
-	fd = open(path, O_RDONLY);
-	if (fd == -1) {
-		if (errno != ENOENT)
-			index_file_set_syscall_error(index, path, "open()");
-		return NULL;
-	}
-
-	uidlist = i_new(struct maildir_uidlist, 1);
-	uidlist->index = index;
-	uidlist->fname = i_strdup(path);
-	uidlist->input = i_stream_create_file(fd, default_pool, 4096, TRUE);
-
-	/* get header */
-	line = i_stream_read_next_line(uidlist->input);
-	if (line == NULL || sscanf(line, "%u %u %u", &version,
-				   &uidlist->uid_validity,
-				   &uidlist->next_uid) != 3 ||
-	    version != 1) {
-		/* broken file */
-		(void)unlink(path);
-		maildir_uidlist_close(uidlist);
-		return NULL;
-	}
-
-	return uidlist;
-}
-
-int maildir_uidlist_next(struct maildir_uidlist *uidlist,
-			 struct maildir_uidlist_rec *uid_rec)
-{
-	const char *line;
-	unsigned int uid;
-
-	memset(uid_rec, 0, sizeof(*uid_rec));
-
-	line = i_stream_read_next_line(uidlist->input);
-	if (line == NULL)
-		return 0;
-
-	uid = 0;
-	while (*line >= '0' && *line <= '9') {
-		uid = uid*10 + (*line - '0');
-		line++;
-	}
-
-	if (uid == 0 || *line != ' ') {
-		/* invalid file */
-		index_set_error(uidlist->index, "Invalid data in file %s",
-				uidlist->fname);
-		(void)unlink(uidlist->fname);
-		return -1;
-	}
-	if (uid <= uidlist->last_read_uid) {
-		index_set_error(uidlist->index,
-				"UIDs not ordered in file %s (%u > %u)",
-				uidlist->fname, uid, uidlist->last_read_uid);
-		(void)unlink(uidlist->fname);
-		return -1;
-	}
-	if (uid >= uidlist->next_uid) {
-		index_set_error(uidlist->index,
-				"UID larger than next_uid in file %s "
-				"(%u >= %u)", uidlist->fname,
-				uid, uidlist->next_uid);
-		(void)unlink(uidlist->fname);
-		return -1;
-	}
-
-	while (*line == ' ') line++;
-
-	uid_rec->uid = uid;
-	uid_rec->filename = line;
-	return 1;
-}
-
-void maildir_uidlist_close(struct maildir_uidlist *uidlist)
-{
-	i_stream_unref(uidlist->input);
-	i_free(uidlist->fname);
-	i_free(uidlist);
-}
-
-static int maildir_uidlist_rewrite_fd(struct mail_index *index,
-				      const char *temp_path, time_t *mtime)
-{
-	struct mail_index_record *rec;
-	struct utimbuf ut;
-	const char *p, *fname;
-	string_t *str;
-	size_t len;
-
-	str = t_str_new(4096);
-	str_printfa(str, "1 %u %u\n",
-		    index->header->uid_validity, index->header->next_uid);
-
-	rec = index->lookup(index, 1);
-	while (rec != NULL) {
-		fname = maildir_get_location(index, rec, NULL);
-		/* maildir should be synced, so above call should never fail */
-		i_assert(fname != NULL);
-
-		p = strchr(fname, ':');
-		len = p == NULL ? strlen(fname) : (size_t)(p-fname);
-
-		if (str_len(str) + MAX_INT_STRLEN + len + 2 >= 4096) {
-			/* flush buffer */
-			if (write_full(index->maildir_lock_fd,
-				       str_data(str), str_len(str)) < 0) {
-				index_file_set_syscall_error(index, temp_path,
-							     "write_full()");
-				return FALSE;
-			}
-			str_truncate(str, 0);
-		}
-
-		str_printfa(str, "%u ", rec->uid);
-		str_append_n(str, fname, len);
-		str_append_c(str, '\n');
-
-		rec = index->next(index, rec);
-	}
-
-	if (write_full(index->maildir_lock_fd,
-		       str_data(str), str_len(str)) < 0) {
-		index_file_set_syscall_error(index, temp_path, "write_full()");
-		return FALSE;
-	}
-
-	/* uidlist's mtime must grow every time */
-	*mtime = ioloop_time > *mtime ? ioloop_time : *mtime + 1;
-	ut.actime = ioloop_time;
-	ut.modtime = *mtime;
-	if (utime(temp_path, &ut) < 0)
-		index_set_syscall_error(index, "utime()");
-
-	if (fsync(index->maildir_lock_fd) < 0) {
-		index_file_set_syscall_error(index, temp_path, "fsync()");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-int maildir_uidlist_rewrite(struct mail_index *index, time_t *mtime)
-{
-	const char *temp_path, *db_path;
-	int failed = FALSE;
-
-	i_assert(INDEX_IS_UIDLIST_LOCKED(index));
-
-	if (index->lock_type == MAIL_LOCK_UNLOCK) {
-		if (!index->set_lock(index, MAIL_LOCK_SHARED))
-			return FALSE;
-	}
-
-	temp_path = t_strconcat(index->control_dir,
-				"/" MAILDIR_UIDLIST_NAME ".lock", NULL);
-
-	failed = !maildir_uidlist_rewrite_fd(index, temp_path, mtime);
-
-	if (!failed) {
-		db_path = t_strconcat(index->control_dir,
-				      "/" MAILDIR_UIDLIST_NAME, NULL);
-
-		if (file_dotlock_replace(db_path, index->maildir_lock_fd,
-					 FALSE) <= 0) {
-			index_set_error(index,
-					"file_dotlock_replace(%s) failed: %m",
-					db_path);
-			failed = TRUE;
-		}
-	} else {
-		(void)close(index->maildir_lock_fd);
-	}
-        index->maildir_lock_fd = -1;
-
-	if (failed)
-		(void)unlink(temp_path);
-	return !failed;
-}
--- a/src/lib-index/maildir/maildir-uidlist.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#ifndef __MAILDIR_UIDLIST_H
-#define __MAILDIR_UIDLIST_H
-
-#define INDEX_IS_UIDLIST_LOCKED(index) \
-        ((index)->maildir_lock_fd != -1)
-
-#define MAILDIR_UIDLIST_NAME "dovecot-uidlist"
-
-struct maildir_uidlist {
-	struct mail_index *index;
-	char *fname;
-	struct istream *input;
-
-	unsigned int uid_validity, next_uid, last_read_uid;
-};
-
-struct maildir_uidlist_rec {
-	unsigned int uid;
-	const char *filename;
-};
-
-int maildir_uidlist_try_lock(struct mail_index *index);
-void maildir_uidlist_unlock(struct mail_index *index);
-int maildir_uidlist_rewrite(struct mail_index *index, time_t *mtime);
-
-struct maildir_uidlist *maildir_uidlist_open(struct mail_index *index);
-void maildir_uidlist_close(struct maildir_uidlist *uidlist);
-
-/* Returns -1 if error, 0 if end of file or 1 if found.
-   uid_rec.uid is also set to 0 at EOF. This function does sanity checks so
-   you can be sure that uid_rec.uid is always growing and smaller than
-   uidlist->next_uid. */
-int maildir_uidlist_next(struct maildir_uidlist *uidlist,
-			 struct maildir_uidlist_rec *uid_rec);
-
-/* Try to update cur/ stamp in  */
-int maildir_uidlist_update_cur_stamp(struct maildir_uidlist *uidlist,
-				     time_t stamp);
-
-#endif
--- a/src/lib-index/maildir/maildir-update-flags.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "hash.h"
-#include "ioloop.h"
-#include "maildir-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <stdio.h>
-#include <sys/stat.h>
-
-struct update_flags_ctx {
-	const char *new_fname;
-	int found;
-
-        enum modify_type modify_type;
-	enum mail_flags flags;
-};
-
-static int update_filename(struct mail_index *index,
-			   struct mail_index_record *rec)
-{
-	const char *old_fname, *old_path, *new_fname, *new_path;
-	enum mail_index_record_flag flags;
-
-	old_fname = maildir_get_location(index, rec, NULL);
-	if (old_fname == NULL)
-		return -1;
-
-	flags = mail_cache_get_index_flags(index->cache, rec);
-
-	old_path = t_strconcat(index->mailbox_path,
-			       (flags & MAIL_INDEX_FLAG_MAILDIR_NEW) != 0 ?
-			       "/new/" : "/cur/", old_fname, NULL);
-
-	new_fname = maildir_filename_set_flags(old_fname, rec->msg_flags);
-	new_path = t_strconcat(index->mailbox_path, "/cur/", new_fname, NULL);
-
-	if (strcmp(old_path, new_path) == 0 ||
-	    rename(old_path, new_path) == 0) {
-		flags &= ~(MAIL_INDEX_FLAG_DIRTY | MAIL_INDEX_FLAG_MAILDIR_NEW);
-		if (!mail_cache_update_index_flags(index->cache, rec, flags))
-			return -1;
-		return 1;
-	} else {
-		if (errno != ENOENT && errno != EACCES &&
-		    !ENOSPACE(errno)) {
-			index_set_error(index,
-					"rename(%s, %s) failed: %m",
-					old_path, new_path);
-			return -1;
-		}
-		return 0;
-	}
-}
-
-int maildir_try_flush_dirty_flags(struct mail_index *index, int force)
-{
-	struct mail_index_record *rec;
-	int ret, dirty = FALSE;
-
-	if (index->next_dirty_flags_flush == 0 ||
-	    (ioloop_time < index->next_dirty_flags_flush && !force))
-		return TRUE;
-
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	ret = mail_cache_lock(index->cache, !force);
-	if (ret <= 0)
-		return ret == 0;
-        mail_cache_unlock_later(index->cache);
-
-	rec = index->lookup(index, 1);
-	while (rec != NULL) {
-		if ((mail_cache_get_index_flags(index->cache, rec) &
-		     MAIL_INDEX_FLAG_DIRTY) != 0) {
-			ret = update_filename(index, rec);
-			if (ret < 0)
-				break;
-			if (ret == 0)
-				dirty = TRUE;
-		}
-
-		rec = index->next(index, rec);
-	}
-
-	if (ret < 0)
-		return FALSE;
-
-	if (!dirty) {
-		index->header->flags &= ~MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES;
-		index->next_dirty_flags_flush = 0;
-	} else {
-		index->next_dirty_flags_flush =
-			ioloop_time + MAILDIR_DIRTY_FLUSH_TIMEOUT;
-	}
-
-	return TRUE;
-}
-
-static int do_rename(struct mail_index *index, const char *path, void *context)
-{
-	struct update_flags_ctx *ctx = context;
-	const char *fname, *new_path;
-	enum mail_flags old_flags, new_flags;
-	int new_dir;
-
-        old_flags = maildir_filename_get_flags(path, 0);
-	switch (ctx->modify_type) {
-	case MODIFY_ADD:
-		new_flags = old_flags | ctx->flags;
-		break;
-	case MODIFY_REMOVE:
-		new_flags = old_flags & ~ctx->flags;
-		break;
-	case MODIFY_REPLACE:
-		new_flags = ctx->flags |
-			(old_flags & index->private_flags_mask);
-		break;
-	default:
-		new_flags = 0;
-		i_unreached();
-	}
-
-	fname = strrchr(path, '/');
-	ctx->new_fname = maildir_filename_set_flags(fname != NULL ?
-						    fname+1 : path, new_flags);
-
-	if (old_flags == new_flags) {
-		/* it's what we wanted. verify that the file exists, but
-		   only if something actually could have changed
-		   (ie. do nothing with private flag changes in shared
-		   mailboxes). */
-		struct stat st;
-
-		if (ctx->flags != 0) {
-			if (stat(path, &st) < 0) {
-				if (errno == ENOENT)
-					return 0;
-				index_file_set_syscall_error(index, path,
-							     "stat()");
-				return -1;
-			}
-		}
-		ctx->found = TRUE;
-		return 1;
-	}
-
-	new_dir = fname != NULL && path + 4 <= fname &&
-		strncmp(fname-4, "/new", 4) == 0;
-	if (new_dir) {
-		/* move from new/ to cur/ */
-		new_path = t_strconcat(t_strdup_until(path, fname-4),
-				       "/cur/", ctx->new_fname, NULL);
-	} else {
-		new_path = maildir_filename_set_flags(path, new_flags);
-	}
-
-	if (rename(path, new_path) < 0) {
-		if (errno == ENOENT)
-			return 0;
-
-		if (ENOSPACE(errno)) {
-			index->nodiskspace = TRUE;
-			return 1;
-		}
-
-		if (errno == EACCES) {
-			index->mailbox_readonly = TRUE;
-			return 1;
-		}
-
-		index_set_error(index, "rename(%s, %s) failed: %m",
-				path, new_path);
-		return -1;
-	}
-
-	if (index->maildir_keep_new && new_dir) {
-		/* looks like we have some more space again, see if we could
-		   move mails from new/ to cur/ again */
-		index->maildir_keep_new = FALSE;
-	}
-
-	/* cur/ was updated, set it dirty-synced */
-	index->sync_stamp = ioloop_time;
-	index->sync_dirty_stamp = ioloop_time;
-	ctx->found = TRUE;
-	return 1;
-}
-
-int maildir_index_update_flags(struct mail_index *index,
-			       struct mail_index_record *rec, unsigned int seq,
-			       enum modify_type modify_type,
-			       enum mail_flags flags, int external_change)
-{
-	struct update_flags_ctx ctx;
-        enum mail_index_record_flag index_flags;
-
-	memset(&ctx, 0, sizeof(ctx));
-	ctx.modify_type = modify_type;
-	ctx.flags = flags & ~index->private_flags_mask;
-
-	t_push();
-	if (!maildir_file_do(index, rec, do_rename, &ctx)) {
-		t_pop();
-		return FALSE;
-	}
-
-	if (!ctx.found) {
-		/* we couldn't actually rename() the file now.
-		   leave it's flags dirty so they get changed later. */
-		index_flags = mail_cache_get_index_flags(index->cache, rec);
-		if ((index_flags & MAIL_INDEX_FLAG_DIRTY) == 0) {
-			if (mail_cache_lock(index->cache, FALSE) <= 0)
-				return FALSE;
-			mail_cache_unlock_later(index->cache);
-
-			index_flags |= MAIL_INDEX_FLAG_DIRTY;
-			mail_cache_update_index_flags(index->cache, rec,
-						      index_flags);
-
-			index->header->flags |=
-				MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES;
-		}
-
-		index->next_dirty_flags_flush =
-			ioloop_time + MAILDIR_DIRTY_FLUSH_TIMEOUT;
-	} else if (ctx.new_fname != NULL) {
-		maildir_index_update_filename(index, rec->uid,
-					      ctx.new_fname, FALSE);
-	}
-	t_pop();
-
-	return mail_index_update_flags(index, rec, seq,
-				       modify_type, flags, external_change);
-}
--- a/src/lib-index/mbox/istream-mbox.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "buffer.h"
-#include "message-parser.h"
-#include "istream-internal.h"
-#include "mbox-index.h"
-
-struct mbox_istream {
-	struct _istream istream;
-
-	struct istream *input;
-
-	buffer_t *headers;
-	uoff_t v_header_size, body_offset, body_size;
-};
-
-static void _close(struct _iostream *stream __attr_unused__)
-{
-}
-
-static void _destroy(struct _iostream *stream)
-{
-	struct mbox_istream *mstream = (struct mbox_istream *) stream;
-
-	i_stream_unref(mstream->input);
-	buffer_free(mstream->headers);
-}
-
-static void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
-{
-	struct mbox_istream *mstream = (struct mbox_istream *) stream;
-
-	i_stream_set_max_buffer_size(mstream->input, max_size);
-}
-
-static void _set_blocking(struct _iostream *stream, int timeout_msecs,
-			  void (*timeout_cb)(void *), void *context)
-{
-	struct mbox_istream *mstream = (struct mbox_istream *) stream;
-
-	i_stream_set_blocking(mstream->input, timeout_msecs,
-			      timeout_cb, context);
-}
-
-static ssize_t _read(struct _istream *stream)
-{
-	struct mbox_istream *mstream = (struct mbox_istream *) stream;
-	ssize_t ret;
-	size_t pos;
-	uoff_t offset;
-
-	if (stream->istream.v_offset < mstream->v_header_size) {
-		/* we don't support mixing headers and body.
-		   it shouldn't be needed. */
-		return -2;
-	}
-
-	offset = stream->istream.v_offset - mstream->v_header_size;
-	if (mstream->input->v_offset != offset)
-		i_stream_seek(mstream->input, offset);
-
-	ret = i_stream_read(mstream->input);
-
-	stream->pos -= stream->skip;
-	stream->skip = 0;
-	stream->buffer = i_stream_get_data(mstream->input, &pos);
-
-	ret = pos <= stream->pos ? -1 :
-		(ssize_t) (pos - stream->pos);
-	mstream->istream.pos = pos;
-	return ret;
-}
-
-static void _seek(struct _istream *stream, uoff_t v_offset)
-{
-	struct mbox_istream *mstream = (struct mbox_istream *) stream;
-
-	stream->istream.v_offset = v_offset;
-	if (v_offset < mstream->v_header_size) {
-		/* still in headers */
-		stream->skip = v_offset;
-		stream->pos = mstream->v_header_size;
-		stream->buffer = buffer_get_data(mstream->headers, NULL);
-	} else {
-		/* body - use our real input stream */
-		stream->skip = stream->pos = 0;
-		stream->buffer = NULL;
-	}
-}
-
-struct istream *i_stream_create_mbox(pool_t pool, struct istream *input,
-				     uoff_t offset, uoff_t body_size)
-{
-	struct mbox_istream *mstream;
-	struct istream *hdr_input;
-
-	mstream = p_new(pool, struct mbox_istream, 1);
-	mstream->body_size = body_size;
-
-	if (body_size == 0) {
-		/* possibly broken message, find the next From-line
-		   and make sure header parser won't pass it. */
-		mbox_skip_header(input);
-		hdr_input = i_stream_create_limit(pool, input,
-						  0, input->v_offset);
-	} else {
-		hdr_input = input;
-		i_stream_ref(input);
-	}
-
-	mstream->headers = buffer_create_dynamic(default_pool,
-						 8192, (size_t)-1);
-	i_stream_seek(hdr_input, offset);
-	mbox_read_headers(hdr_input, mstream->headers);
-	mstream->v_header_size = buffer_get_used_size(mstream->headers);
-	mstream->body_offset = hdr_input->v_offset;
-	i_stream_unref(hdr_input);
-
-	mstream->input = i_stream_create_limit(pool, input,
-					       mstream->body_offset, body_size);
-
-	mstream->istream.buffer = buffer_get_data(mstream->headers, NULL);
-	mstream->istream.pos = mstream->v_header_size;
-
-	mstream->istream.iostream.close = _close;
-	mstream->istream.iostream.destroy = _destroy;
-	mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
-	mstream->istream.iostream.set_blocking = _set_blocking;
-
-	mstream->istream.read = _read;
-	mstream->istream.seek = _seek;
-
-	return _i_stream_create(&mstream->istream, pool, -1,
-				input->real_stream->abs_start_offset);
-}
--- a/src/lib-index/mbox/mbox-append.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "istream.h"
-#include "hex-binary.h"
-#include "md5.h"
-#include "mbox-index.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-static int mbox_index_append_next(struct mail_index *index,
-				  struct mail_cache_transaction_ctx *trans_ctx,
-				  struct istream *input)
-{
-	struct mail_index_record *rec;
-	struct mbox_header_context ctx;
-	struct istream *hdr_stream;
-	enum mail_index_record_flag index_flags;
-	time_t received_date;
-	uoff_t hdr_offset, body_offset, end_offset;
-	const unsigned char *data;
-	unsigned char md5_digest[16];
-	size_t size, pos;
-	int dirty, save_md5 = FALSE;
-
-	/* get the From-line */
-	pos = 0;
-	while (i_stream_read_data(input, &data, &size, pos) > 0) {
-		for (; pos < size; pos++) {
-			if (data[pos] == '\n')
-				break;
-		}
-
-		if (pos < size)
-			break;
-	}
-
-	if (size == 0)
-		return -2;
-
-	if (pos == size || size <= 5 || memcmp(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->mailbox_path);
-		index->set_flags |= MAIL_INDEX_HDR_FLAG_FSCK;
-		return -1;
-	}
-
-	/* parse the From-line */
-	received_date = mbox_from_parse_date(data + 5, size - 5);
-	if (received_date == (time_t)-1)
-		received_date = ioloop_time;
-
-	i_stream_skip(input, pos+1);
-	hdr_offset = input->v_offset;
-
-	/* now, find the end of header. also stops at "\nFrom " if it's
-	   found (broken messages) */
-	mbox_skip_header(input);
-	body_offset = input->v_offset;
-
-	index_flags = 0;
-
-	/* parse the header and cache wanted fields. get the message flags
-	   from Status and X-Status fields. temporarily limit the stream length
-	   so the message body is parsed properly.
-
-	   the stream length limit is raised again by mbox_header_cb after
-	   reading the headers. it uses Content-Length if available or finds
-	   the next From-line. */
-	mbox_header_init_context(&ctx, index, input);
-
-	hdr_stream = i_stream_create_limit(default_pool, input,
-					   hdr_offset,
-					   body_offset - hdr_offset);
-	i_stream_seek(hdr_stream, 0);
-	message_parse_header(NULL, hdr_stream, NULL, mbox_header_cb, &ctx);
-	i_stream_unref(hdr_stream);
-
-	dirty = FALSE;
-
-	/* try Content-Length */
-	end_offset = body_offset + ctx.content_length;
-	if (ctx.content_length == (uoff_t)-1 ||
-	    !mbox_verify_end_of_body(input, end_offset)) {
-		/* failed, search for From-line */
-		if (ctx.content_length != (uoff_t)-1) {
-			/* broken, rewrite it */
-			dirty = TRUE;
-		}
-
-		i_stream_seek(input, body_offset);
-		mbox_skip_message(input);
-		ctx.content_length = input->v_offset - body_offset;
-	}
-
-	if (index->header->messages_count == 0 &&
-	    ctx.uid_validity != index->header->uid_validity) {
-		/* UID validity is different */
-		if (ctx.uid_validity != 0) {
-			/* change it in index */
-			index->header->uid_validity = ctx.uid_validity;
-			index->header->next_uid = 1;
-			index->header->last_nonrecent_uid = 0;
-			index->inconsistent = TRUE;
-		} else if (!index->mailbox_readonly) {
-			/* we have to write it to mbox */
-			if (index->mbox_lock_type != MAIL_LOCK_EXCLUSIVE) {
-				/* try again */
-				return 0;
-			}
-
-			dirty = TRUE;
-		}
-	}
-
-	if (ctx.uid >= index->header->next_uid) {
-		/* X-UID header looks ok */
-		index->header->next_uid = ctx.uid;
-	} else if (!index->mailbox_readonly) {
-		/* Write X-UID for it */
-		dirty = TRUE;
-	} else {
-		/* save MD5 */
-                save_md5 = TRUE;
-	}
-
-	if (dirty && !index->mailbox_readonly) {
-		if (index->mbox_lock_type != MAIL_LOCK_EXCLUSIVE) {
-			/* try again */
-			return 0;
-		}
-
-		index->header->flags |= MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES;
-		index_flags |= MAIL_INDEX_FLAG_DIRTY;
-	}
-
-	/* add message to index */
-	rec = index->append(index);
-	if (rec == NULL)
-		return -1;
-
-	/* save message flags */
-	rec->msg_flags = ctx.flags;
-	mail_index_mark_flag_changes(index, rec, 0, rec->msg_flags);
-
-	if (!mail_cache_add(trans_ctx, rec, MAIL_CACHE_INDEX_FLAGS,
-			    &index_flags, sizeof(index_flags)))
-		return -1;
-
-	/* location offset = beginning of headers in message */
-	if (!mail_cache_add(trans_ctx, rec, MAIL_CACHE_LOCATION_OFFSET,
-			    &hdr_offset, sizeof(hdr_offset)))
-		return -1;
-
-	if (!mail_cache_add(trans_ctx, rec, MAIL_CACHE_RECEIVED_DATE,
-			    &received_date, sizeof(received_date)))
-		return -1;
-
-	if (!mail_cache_add(trans_ctx, rec, MAIL_CACHE_PHYSICAL_BODY_SIZE,
-			    &ctx.content_length, sizeof(ctx.content_length)))
-		return -1;
-
-	if (save_md5) {
-		md5_final(&ctx.md5, md5_digest);
-
-		if (!mail_cache_add(trans_ctx, rec, MAIL_CACHE_MD5,
-				    md5_digest, sizeof(md5_digest)))
-			return -1;
-	}
-
-	return 1;
-}
-
-int mbox_index_append_stream(struct mail_index *index, struct istream *input)
-{
-	struct mail_cache_transaction_ctx *trans_ctx;
-	uoff_t offset;
-	int ret;
-
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return -1;
-
-	if (mail_cache_transaction_begin(index->cache, TRUE, &trans_ctx) <= 0)
-		return -1;
-
-	do {
-		offset = input->v_offset;
-		if (input->v_offset != 0) {
-			/* we're at the [\r]\n before the From-line,
-			   skip it */
-			if (!mbox_skip_crlf(input)) {
-				index_set_error(index,
-						"Error indexing mbox file %s: "
-						"LF not found where expected",
-						index->mailbox_path);
-
-				index->set_flags |= MAIL_INDEX_HDR_FLAG_FSCK;
-				ret = -1;
-				break;
-			}
-		}
-
-		t_push();
-		ret = mbox_index_append_next(index, trans_ctx, input);
-		t_pop();
-
-		if (ret == -2) {
-			/* EOF */
-			ret = 1;
-			break;
-		}
-
-		if (ret == 0) {
-			/* we want to rescan this message with exclusive
-			   locking */
-			i_stream_seek(input, offset);
-		}
-	} while (ret > 0);
-
-	if (ret >= 0 && index->mbox_lock_type == MAIL_LOCK_EXCLUSIVE) {
-		/* Write missing X-IMAPbase and new/changed X-UID headers */
-		if (!mbox_index_rewrite(index))
-			ret = -1;
-	}
-
-	if (ret >= 0) {
-		if (!mail_cache_transaction_commit(trans_ctx))
-			ret = -1;
-	}
-	if (!mail_cache_transaction_end(trans_ctx))
-		ret = -1;
-
-	return ret;
-}
--- a/src/lib-index/mbox/mbox-from.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "str.h"
-#include "utc-mktime.h"
-#include "mbox-index.h"
-
-#include <time.h>
-#include <ctype.h>
-
-static const char *weekdays[] = {
-	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-static const char *months[] = {
-	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
-{
-	const unsigned char *msg_end;
-	struct tm tm;
-	int i, timezone;
-	time_t t;
-
-	/* <sender> <date> <moreinfo> */
-	msg_end = msg + size;
-
-	/* skip sender */
-	while (msg < msg_end && *msg != ' ') {
-		if (*msg == '\r' || *msg == '\n')
-			return (time_t)-1;
-		msg++;
-	}
-	while (msg < msg_end && *msg == ' ') msg++;
-
-	/* next 24 chars should be in the date in asctime() format, eg.
-	   "Thu Nov 29 22:33:52 2001 +0300"
-
-	   Some also include named timezone, which we ignore:
-
-	   "Thu Nov 29 22:33:52 EEST 2001"
-	*/
-	if (msg+24 > msg_end)
-		return (time_t)-1;
-
-	memset(&tm, 0, sizeof(tm));
-
-	/* skip weekday */
-	msg += 4;
-
-	/* month */
-	for (i = 0; i < 12; i++) {
-		if (memcasecmp(months[i], msg, 3) == 0) {
-			tm.tm_mon = i;
-			break;
-		}
-	}
-
-	if (i == 12 && memcmp(msg, "???", 3) == 0) {
-		/* just a hack to parse one special mbox I have :) */
-		i = 0;
-	}
-
-	if (i == 12 || msg[3] != ' ')
-		return (time_t)-1;
-	msg += 4;
-
-	/* day */
-	if (msg[0] == ' ') {
-		if (!i_isdigit(msg[1]) || msg[2] != ' ')
-			return (time_t)-1;
-		tm.tm_mday = msg[1]-'0';
-	} else {
-		if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
-			return (time_t)-1;
-		tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0');
-	}
-	if (tm.tm_mday == 0)
-		tm.tm_mday = 1;
-	msg += 3;
-
-	/* hour */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
-		return (time_t)-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;
-	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;
-	tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0');
-	msg += 3;
-
-	/* optional named timezone */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
-	    !i_isdigit(msg[2]) || !i_isdigit(msg[3])) {
-		/* skip to next space */
-		while (msg < msg_end && *msg != ' ') {
-			if (*msg == '\r' || *msg == '\n')
-				return (time_t)-1;
-			msg++;
-		}
-		if (msg+5 > msg_end)
-			return (time_t)-1;
-		msg++;
-	}
-
-	/* year */
-	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
-	    !i_isdigit(msg[2]) || !i_isdigit(msg[3]))
-		return (time_t)-1;
-
-	tm.tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 +
-		(msg[2]-'0') * 10 + (msg[3]-'0') - 1900;
-	msg += 4;
-
-	tm.tm_isdst = -1;
-	if (msg[0] == ' ' && (msg[1] == '-' || msg[1] == '+') &&
-	    i_isdigit(msg[2]) && i_isdigit(msg[3]) &&
-	    i_isdigit(msg[4]) && i_isdigit(msg[5])) {
-		timezone = (msg[2]-'0') * 1000 + (msg[3]-'0') * 100 +
-			(msg[4]-'0') * 10 +(msg[5]-'0');
-		if (msg[1] == '-') timezone = -timezone;
-
-		t = utc_mktime(&tm);
-		if (t == (time_t)-1)
-			return (time_t)-1;
-
-		t -= timezone * 60;
-		return t;
-	} else {
-		/* assume local timezone */
-		return mktime(&tm);
-	}
-}
-
-const char *mbox_from_create(const char *sender, time_t time)
-{
-	string_t *str;
-	struct tm *tm;
-	int year;
-
-	str = t_str_new(256);
-	str_append(str, "From ");
-	str_append(str, sender);
-	str_append(str, "  ");
-
-	/* we could use simply asctime(), but i18n etc. may break it.
-	   Example: "Thu Nov 29 22:33:52 2001" */
-	tm = localtime(&time);
-
-	/* week day */
-	str_append(str, weekdays[tm->tm_wday]);
-	str_append_c(str, ' ');
-
-	/* month */
-	str_append(str, months[tm->tm_mon]);
-	str_append_c(str, ' ');
-
-	/* day */
-	str_append_c(str, (tm->tm_mday / 10) + '0');
-	str_append_c(str, (tm->tm_mday % 10) + '0');
-	str_append_c(str, ' ');
-
-	/* hour */
-	str_append_c(str, (tm->tm_hour / 10) + '0');
-	str_append_c(str, (tm->tm_hour % 10) + '0');
-	str_append_c(str, ':');
-
-	/* minute */
-	str_append_c(str, (tm->tm_min / 10) + '0');
-	str_append_c(str, (tm->tm_min % 10) + '0');
-	str_append_c(str, ':');
-
-	/* second */
-	str_append_c(str, (tm->tm_sec / 10) + '0');
-	str_append_c(str, (tm->tm_sec % 10) + '0');
-	str_append_c(str, ' ');
-
-	/* year */
-	year = tm->tm_year + 1900;
-	str_append_c(str, (year / 1000) + '0');
-	str_append_c(str, ((year / 100) % 10) + '0');
-	str_append_c(str, ((year / 10) % 10) + '0');
-	str_append_c(str, (year % 10) + '0');
-
-	str_append_c(str, '\n');
-	return str_c(str);
-}
--- a/src/lib-index/mbox/mbox-index.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,865 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "buffer.h"
-#include "istream.h"
-#include "message-part-serialize.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
-#include "mail-index-util.h"
-#include "mail-custom-flags.h"
-#include "mail-cache.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-/* Don't try reading more custom flags than this. */
-#define MAX_CUSTOM_FLAGS 1024
-
-extern struct mail_index mbox_index;
-
-int mbox_set_syscall_error(struct mail_index *index, const char *function)
-{
-	i_assert(function != NULL);
-
-	index_set_error(index, "%s failed with mbox file %s: %m",
-			function, index->mailbox_path);
-	return FALSE;
-}
-
-int mbox_file_open(struct mail_index *index)
-{
-	struct stat st;
-	int fd;
-
-	i_assert(index->mbox_fd == -1);
-
-	fd = open(index->mailbox_path, index->mailbox_readonly ?
-		  O_RDONLY : O_RDWR);
-	if (fd == -1) {
-		mbox_set_syscall_error(index, "open()");
-		return FALSE;
-	}
-
-	if (fstat(fd, &st) < 0) {
-		mbox_set_syscall_error(index, "fstat()");
-		(void)close(fd);
-		return FALSE;
-	}
-
-	index->mbox_fd = fd;
-	index->mbox_dev = st.st_dev;
-	index->mbox_ino = st.st_ino;
-	return TRUE;
-}
-
-struct istream *mbox_get_stream(struct mail_index *index,
-				enum mail_lock_type lock_type)
-{
-	switch (lock_type) {
-	case MAIL_LOCK_SHARED:
-	case MAIL_LOCK_EXCLUSIVE:
-		/* don't drop exclusive lock, it may be there for a reason */
-		if (index->mbox_lock_type != MAIL_LOCK_EXCLUSIVE) {
-			if (!mbox_lock(index, lock_type))
-				return NULL;
-		}
-		break;
-	default:
-		if (index->mbox_fd == -1) {
-			if (!mbox_file_open(index))
-				return NULL;
-		}
-		break;
-	}
-
-	if (index->mbox_stream == NULL) {
-		if (index->mail_read_mmaped) {
-			index->mbox_stream =
-				i_stream_create_mmap(index->mbox_fd,
-						     default_pool,
-						     MAIL_MMAP_BLOCK_SIZE,
-						     0, 0, FALSE);
-		} else {
-			index->mbox_stream =
-				i_stream_create_file(index->mbox_fd,
-						     default_pool,
-						     MAIL_READ_BLOCK_SIZE,
-						     FALSE);
-		}
-	}
-
-	i_stream_seek(index->mbox_stream, 0);
-	i_stream_ref(index->mbox_stream);
-	return index->mbox_stream;
-}
-
-void mbox_file_close_stream(struct mail_index *index)
-{
-	if (index->mbox_stream != NULL) {
-		i_stream_close(index->mbox_stream);
-		i_stream_unref(index->mbox_stream);
-		index->mbox_stream = NULL;
-	}
-}
-
-void mbox_file_close_fd(struct mail_index *index)
-{
-	mbox_file_close_stream(index);
-
-	if (index->mbox_fd != -1) {
-		if (close(index->mbox_fd) < 0)
-			i_error("close(mbox) failed: %m");
-		index->mbox_fd = -1;
-	}
-}
-
-void mbox_header_init_context(struct mbox_header_context *ctx,
-			      struct mail_index *index,
-			      struct istream *input)
-{
-	memset(ctx, 0, sizeof(struct mbox_header_context));
-	md5_init(&ctx->md5);
-
-	ctx->index = index;
-	ctx->input = input;
-	ctx->custom_flags = mail_custom_flags_list_get(index->custom_flags);
-	ctx->content_length = (uoff_t)-1;
-}
-
-static enum mail_flags
-mbox_get_status_flags(const unsigned char *value, size_t len)
-{
-	enum mail_flags flags;
-	size_t i;
-
-	flags = 0;
-	for (i = 0; i < len; i++) {
-		switch (value[i]) {
-		case 'A':
-			flags |= MAIL_ANSWERED;
-			break;
-		case 'F':
-			flags |= MAIL_FLAGGED;
-			break;
-		case 'T':
-			flags |= MAIL_DRAFT;
-			break;
-		case 'R':
-			flags |= MAIL_SEEN;
-			break;
-		case 'D':
-			flags |= MAIL_DELETED;
-			break;
-		}
-	}
-
-	return flags;
-}
-
-static void mbox_update_custom_flags(const unsigned char *value __attr_unused__,
-				     size_t len __attr_unused__,
-				     int index, void *context)
-{
-	enum mail_flags *flags = context;
-
-	if (index >= 0)
-		*flags |= 1 << (index + MAIL_CUSTOM_FLAG_1_BIT);
-}
-
-static enum mail_flags
-mbox_get_keyword_flags(const unsigned char *value, size_t len,
-		       const char *custom_flags[MAIL_CUSTOM_FLAGS_COUNT])
-{
-	enum mail_flags flags;
-
-	flags = 0;
-	mbox_keywords_parse(value, len, custom_flags,
-			    mbox_update_custom_flags, &flags);
-	return flags;
-}
-
-static void mbox_parse_imapbase(const unsigned char *value, size_t len,
-				struct mbox_header_context *ctx)
-{
-	const char *flag, *str;
-	char *end;
-	buffer_t *buf;
-	size_t pos, start;
-	enum mail_flags flags;
-	unsigned int count;
-	int ret;
-
-	t_push();
-
-	/* <uid validity> <last uid> */
-	str = t_strndup(value, len);
-	ctx->uid_validity = strtoul(str, &end, 10);
-	ctx->uid_last = strtoul(end, &end, 10);
-	pos = end - str;
-
-	while (pos < len && value[pos] == ' ')
-		pos++;
-
-	if (pos == len) {
-		t_pop();
-		return;
-	}
-
-	/* we're at the 3rd field now, which begins the list of custom flags */
-	buf = buffer_create_dynamic(pool_datastack_create(),
-				    MAIL_CUSTOM_FLAGS_COUNT *
-				    sizeof(const char *),
-				    MAX_CUSTOM_FLAGS * sizeof(const char *));
-	for (start = pos; ; pos++) {
-		if (pos == len || value[pos] == ' ' || value[pos] == '\t') {
-			if (start != pos) {
-				flag = t_strdup_until(value+start, value+pos);
-				if (buffer_append(buf, &flag,
-						  sizeof(flag)) == 0)
-					break;
-			}
-			start = pos+1;
-
-			if (pos == len)
-				break;
-		}
-	}
-
-	flags = MAIL_CUSTOM_FLAGS_MASK;
-	count = buffer_get_used_size(buf) / sizeof(const char *);
-	ret = mail_custom_flags_fix_list(ctx->index->custom_flags, &flags,
-					 buffer_free_without_data(buf), count);
-
-	t_pop();
-}
-
-void mbox_header_cb(struct message_part *part __attr_unused__,
-		    struct message_header_line *hdr, void *context)
-{
-	struct mbox_header_context *ctx = context;
-	size_t i;
-	int fixed = FALSE;
-
-	if (hdr == NULL || hdr->eoh)
-		return;
-
-	/* Pretty much copy&pasted from popa3d by Solar Designer */
-	switch (*hdr->name) {
-	case 'R':
-	case 'r':
-		if (!ctx->received &&
-		    strcasecmp(hdr->name, "Received") == 0) {
-			/* get only the first received-header */
-			fixed = TRUE;
-			if (!hdr->continues)
-				ctx->received = TRUE;
-		}
-		break;
-
-	case 'C':
-	case 'c':
-		if (strcasecmp(hdr->name, "Content-Length") == 0) {
-			/* manual parsing, so we can deal with uoff_t */
-			ctx->content_length = 0;
-			for (i = 0; i < hdr->value_len; i++) {
-				if (hdr->value[i] < '0' ||
-				    hdr->value[i] > '9') {
-					/* invalid */
-					ctx->content_length = 0;
-					break;
-				}
-
-				ctx->content_length = ctx->content_length * 10 +
-					(hdr->value[i] - '0');
-			}
-		}
-		break;
-
-	case 'D':
-	case 'd':
-		if (strcasecmp(hdr->name, "Delivered-To") == 0)
-			fixed = TRUE;
-		else if (!ctx->received && strcasecmp(hdr->name, "Date") == 0) {
-			/* Received-header contains date too,
-			   and more trusted one */
-			fixed = TRUE;
-		}
-		break;
-
-	case 'M':
-	case 'm':
-		if (!ctx->received &&
-		    strcasecmp(hdr->name, "Message-ID") == 0) {
-			/* Received-header contains unique ID too,
-			   and more trusted one */
-			fixed = TRUE;
-		}
-		break;
-
-	case 'S':
-	case 's':
-		if (strcasecmp(hdr->name, "Status") == 0) {
-			/* update message flags */
-			ctx->flags |= mbox_get_status_flags(hdr->value,
-							    hdr->value_len);
-		}
-		break;
-
-	case 'X':
-	case 'x':
-		if (strcasecmp(hdr->name, "X-Delivery-ID:") == 0) {
-			/* 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. */
-			fixed = TRUE;
-		} else if (strcasecmp(hdr->name, "X-UID") == 0) {
-			ctx->uid = 0;
-			for (i = 0; i < hdr->value_len; i++) {
-				if (hdr->value[i] < '0' ||
-				    hdr->value[i] > '9')
-					break;
-				ctx->uid = ctx->uid * 10 + (hdr->value[i]-'0');
-			}
-		} else if (strcasecmp(hdr->name, "X-Status") == 0) {
-			/* update message flags */
-			ctx->flags |= mbox_get_status_flags(hdr->value,
-							    hdr->value_len);
-		} else if (strcasecmp(hdr->name, "X-Keywords") == 0) {
-			/* update custom message flags */
-			ctx->flags |= mbox_get_keyword_flags(hdr->value,
-							     hdr->value_len,
-							     ctx->custom_flags);
-		} else if (strcasecmp(hdr->name, "X-IMAPbase") == 0) {
-			if (hdr->continues) {
-				hdr->use_full_value = TRUE;
-				break;
-			}
-			mbox_parse_imapbase(hdr->full_value,
-					    hdr->full_value_len, ctx);
-		}
-		break;
-	}
-
-	if (fixed)
-		md5_update(&ctx->md5, hdr->value, hdr->value_len);
-}
-
-void mbox_keywords_parse(const unsigned char *value, size_t len,
-			 const char *custom_flags[MAIL_CUSTOM_FLAGS_COUNT],
-			 void (*func)(const unsigned char *, size_t,
-				      int, void *),
-			 void *context)
-{
-	size_t custom_len[MAIL_CUSTOM_FLAGS_COUNT];
-	size_t item_len;
-	int i;
-
-	/* the value is often empty, so check that first */
-	while (len > 0 && IS_LWSP(*value)) {
-		value++;
-		len--;
-	}
-
-	if (len == 0)
-		return;
-
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-		custom_len[i] = custom_flags[i] != NULL ?
-			strlen(custom_flags[i]) : 0;
-	}
-
-	for (;;) {
-		/* skip whitespace */
-		while (len > 0 && IS_LWSP(*value)) {
-			value++;
-			len--;
-		}
-
-		if (len == 0)
-			break;
-
-		/* find the length of the item */
-		for (item_len = 0; item_len < len; item_len++) {
-			if (IS_LWSP(value[item_len]))
-				break;
-		}
-
-		/* check if it's found */
-		for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-			if (custom_len[i] == item_len &&
-			    memcasecmp(custom_flags[i], value, item_len) == 0)
-				break;
-		}
-
-		if (i == MAIL_CUSTOM_FLAGS_COUNT)
-			i = -1;
-
-		func(value, item_len, i, context);
-
-		value += item_len;
-		len -= item_len;
-	}
-}
-
-int mbox_skip_crlf(struct istream *input)
-{
-	const unsigned char *data;
-	size_t size, pos;
-
-	pos = 0;
-	while (i_stream_read_data(input, &data, &size, pos) > 0) {
-		if (pos == 0) {
-			if (data[0] == '\n') {
-				i_stream_skip(input, 1);
-				return TRUE;
-			}
-			if (data[0] != '\r')
-				return FALSE;
-
-			pos++;
-		}
-
-		if (size > 1 && pos == 1) {
-			if (data[1] != '\n')
-				return FALSE;
-
-			i_stream_skip(input, 2);
-			return TRUE;
-		}
-	}
-
-	/* end of file */
-	return TRUE;
-}
-
-void mbox_skip_empty_lines(struct istream *input)
-{
-	const unsigned char *data;
-	size_t i, size;
-
-	/* skip empty lines at beginning */
-	while (i_stream_read_data(input, &data, &size, 0) > 0) {
-		for (i = 0; i < size; i++) {
-			if (data[i] != '\r' && data[i] != '\n')
-				break;
-		}
-
-		i_stream_skip(input, i);
-
-		if (i < size)
-			break;
-	}
-}
-
-static int mbox_is_valid_from(struct istream *input, size_t startpos)
-{
-	const unsigned char *msg;
-	size_t i, size;
-
-	i = startpos;
-	while (i_stream_read_data(input, &msg, &size, i) > 0) {
-		for (; i < size; i++) {
-			if (msg[i] == '\n') {
-				msg += startpos;
-				i -= startpos;
-				return mbox_from_parse_date(msg, size) !=
-					(time_t)-1;
-			}
-		}
-	}
-
-	return FALSE;
-}
-
-static void mbox_skip_forward(struct istream *input, int header)
-{
-	const unsigned char *msg;
-	size_t i, size, startpos, eoh;
-	int lastmsg, state, new_state;
-
-	/* read until "[\r]\nFrom " is found. assume '\n' at beginning of
-	   buffer */
-	startpos = i = 0; eoh = 0; lastmsg = TRUE;
-	state = '\n';
-	while (i_stream_read_data(input, &msg, &size, startpos) > 0) {
-		for (i = startpos; i < size; i++) {
-			new_state = 0;
-			switch (state) {
-			case '\n':
-				if (msg[i] == 'F')
-					new_state = 'F';
-				else if (header) {
-					if (msg[i] == '\n') {
-						/* \n\n, but if we have
-						   0-byte message body the
-						   following \n may belong
-						   to "From "-line */
-						eoh = i+1;
-						header = FALSE;
-						new_state = '\n';
-					} else if (msg[i] == '\r') {
-						/* possibly \n\r\n */
-						new_state = '\r';
-					}
-				}
-				break;
-			case '\r':
-				if (msg[i] == '\n') {
-					/* \n\r\n */
-					eoh = i+1;
-					header = FALSE;
-					new_state = '\n';
-				}
-				break;
-			case 'F':
-				if (msg[i] == 'r')
-					new_state = 'r';
-				break;
-			case 'r':
-				if (msg[i] == 'o')
-					new_state = 'o';
-				break;
-			case 'o':
-				if (msg[i] == 'm')
-					new_state = 'm';
-				break;
-			case 'm':
-				if (msg[i] == ' ') {
-					int valid;
-
-					valid = mbox_is_valid_from(input, i+1);
-
-					/* we may have trashed msg above,
-					   get it again */
-					msg = i_stream_get_data(input, &size);
-
-					if (valid) {
-						/* Go back "From" */
-						i -= 4;
-
-						/* Go back \n, unless we're at
-						   beginning of buffer */
-						if (i > 0)
-							i--;
-
-						/* Go back \r if it's there */
-						if (i > 0 && msg[i-1] == '\r')
-							i--;
-
-						i_stream_skip(input, i);
-						return;
-					}
-				}
-				break;
-			}
-
-			if (new_state != 0)
-				state = new_state;
-			else if (eoh == 0)
-				state = msg[i] == '\n' ? '\n' : 0;
-			else {
-				/* end of header position confirmed */
-				i_stream_skip(input, eoh);
-				return;
-			}
-		}
-
-		/* Leave enough space to go back "\r\nFrom" plus one for the
-		   end-of-headers check */
-		startpos = i < 7 ? i : 7;
-		i -= startpos;
-
-		if (eoh != 0) {
-			i_assert(i < eoh);
-			eoh -= i;
-		}
-
-		i_stream_skip(input, i);
-	}
-
-	if (eoh != 0) {
-		/* make sure we didn't end with \n\n or \n\r\n. In these
-		   cases the last [\r]\n doesn't belong to our message. */
-		if (eoh < size && (msg[eoh] != '\r' || eoh < size-1)) {
-			i_stream_skip(input, eoh);
-			return;
-		}
-	}
-
-	/* end of file, leave the last [\r]\n */
-	msg = i_stream_get_data(input, &size);
-	if (size == startpos && startpos > 0) {
-		if (msg[startpos-1] == '\n')
-			startpos--;
-		if (startpos > 0 && msg[startpos-1] == '\r')
-			startpos--;
-	}
-
-	i_stream_skip(input, startpos);
-}
-
-void mbox_skip_header(struct istream *input)
-{
-	mbox_skip_forward(input, TRUE);
-}
-
-void mbox_skip_message(struct istream *input)
-{
-	mbox_skip_forward(input, FALSE);
-}
-
-int mbox_verify_end_of_body(struct istream *input, uoff_t end_offset)
-{
-	const unsigned char *data;
-	size_t size;
-
-	i_stream_seek(input, end_offset);
-
-	/* read forward a bit */
-	if (i_stream_read_data(input, &data, &size, 6) < 0)
-		return FALSE;
-
-	/* either there should be the next From-line,
-	   or [\r]\n at end of file */
-	if (size > 0 && data[0] == '\r') {
-		data++; size--;
-	}
-	if (size > 0) {
-		if (data[0] != '\n')
-			return FALSE;
-
-		data++; size--;
-	}
-
-	return size == 0 ||
-		(size >= 5 && strncmp((const char *) data, "From ", 5) == 0);
-}
-
-int mbox_mail_get_location(struct mail_index *index,
-			   struct mail_index_record *rec,
-			   uoff_t *offset, uoff_t *body_size)
-{
-	struct message_size _body_size;
-	const void *data;
-	size_t size;
-
-	if (offset != NULL) {
-		if (!mail_cache_copy_fixed_field(index->cache, rec,
-						 MAIL_CACHE_LOCATION_OFFSET,
-						 offset, sizeof(*offset))) {
-			mail_cache_set_corrupted(index->cache,
-				"Missing location field for record %u",
-				rec->uid);
-			return FALSE;
-		}
-	}
-
-	if (body_size != NULL) {
-		if (mail_cache_copy_fixed_field(index->cache, rec,
-						MAIL_CACHE_PHYSICAL_BODY_SIZE,
-						body_size, sizeof(uoff_t)))
-			return TRUE;
-
-		if (!mail_cache_lookup_field(index->cache, rec,
-					     MAIL_CACHE_MESSAGEPART,
-					     &data, &size)) {
-			mail_cache_set_corrupted(index->cache,
-				"No cached body_size or message_part for "
-				"record %u", rec->uid);
-			return FALSE;
-		}
-		if (!message_part_deserialize_size(data, size,
-						   NULL, &_body_size)) {
-			mail_cache_set_corrupted(index->cache,
-				"Corrupted message_part for record %u",
-				rec->uid);
-			return FALSE;
-		}
-
-		if (body_size != NULL)
-			*body_size = _body_size.physical_size;
-	}
-
-	return TRUE;
-}
-
-void mbox_read_headers(struct istream *input, buffer_t *dest)
-{
-	struct message_header_parser_ctx *hdr_ctx;
-	struct message_header_line *hdr;
-
-	hdr_ctx = message_parse_header_init(input, NULL);
-	while ((hdr = message_parse_header_next(hdr_ctx)) != NULL) {
-		if (hdr->eoh) {
-			buffer_append(dest, "\r\n", 2);
-			break;
-		}
-
-		if ((*hdr->name == 'X' &&
-		     (strcasecmp(hdr->name, "X-UID") == 0 ||
-		      strcasecmp(hdr->name, "X-IMAPbase") == 0 ||
-		      strcasecmp(hdr->name, "X-Status") == 0 ||
-		      strcasecmp(hdr->name, "X-Keywords") == 0)) ||
-		    strcasecmp(hdr->name, "Content-Length") == 0 ||
-		    strcasecmp(hdr->name, "Status") == 0) {
-			/* ignore */
-		} else {
-			if (!hdr->continued) {
-				buffer_append(dest, hdr->name, hdr->name_len);
-				buffer_append(dest, ": ", 2);
-			}
-			buffer_append(dest, hdr->value, hdr->value_len);
-			buffer_append(dest, "\r\n", 2);
-		}
-	}
-	message_parse_header_deinit(hdr_ctx);
-}
-
-struct mail_index *
-mbox_index_alloc(const char *mbox_path, const char *index_dir,
-		 const char *control_dir)
-{
-	struct mail_index *index;
-
-	i_assert(mbox_path != NULL);
-
-	index = i_new(struct mail_index, 1);
-	memcpy(index, &mbox_index, sizeof(struct mail_index));
-
-	index->mbox_fd = -1;
-	index->mbox_sync_counter = (unsigned int)-1;
-	index->mailbox_readonly = access(mbox_path, W_OK) < 0;
-
-	index->mailbox_path = i_strdup(mbox_path);
-	index->control_dir = i_strdup(control_dir);
-	mail_index_init(index, index_dir);
-	return index;
-}
-
-static void mbox_index_free(struct mail_index *index)
-{
-        mbox_file_close_fd(index);
-	mail_index_close(index);
-	i_free(index->dir);
-	i_free(index->mailbox_path);
-	i_free(index->control_dir);
-	i_free(index);
-}
-
-static int mbox_index_set_lock(struct mail_index *index,
-			       enum mail_lock_type lock_type)
-{
-	if (lock_type == MAIL_LOCK_UNLOCK)
-		(void)mbox_unlock(index);
-	return mail_index_set_lock(index, lock_type);
-}
-
-static int mbox_index_try_lock(struct mail_index *index,
-			       enum mail_lock_type lock_type)
-{
-	if (lock_type == MAIL_LOCK_UNLOCK)
-		(void)mbox_unlock(index);
-	return mail_index_try_lock(index, lock_type);
-}
-
-static int mbox_index_expunge(struct mail_index *index,
-			      struct mail_index_record *first_rec,
-			      struct mail_index_record *last_rec,
-			      unsigned int first_seq, unsigned int last_seq,
-			      int external_change)
-{
-	if (!mail_index_expunge(index, first_rec, last_rec,
-				first_seq, last_seq, external_change))
-		return FALSE;
-
-	if (first_seq == 1) {
-		/* Our message containing X-IMAPbase was deleted.
-		   Get it back there. */
-		index->header->flags |= MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES |
-			MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS;
-	}
-	return TRUE;
-}
-
-static int mbox_index_update_flags(struct mail_index *index,
-				   struct mail_index_record *rec,
-				   unsigned int seq,
-				   enum modify_type modify_type,
-				   enum mail_flags flags,
-				   int external_change)
-{
-        enum mail_index_record_flag index_flags;
-
-	if (!mail_index_update_flags(index, rec, seq,
-				     modify_type, flags, external_change))
-		return FALSE;
-
-	if (!external_change) {
-		/* we'll just mark the message as dirty */
-		index_flags = mail_cache_get_index_flags(index->cache, rec);
-		if ((index_flags & MAIL_INDEX_FLAG_DIRTY) == 0) {
-			if (mail_cache_lock(index->cache, FALSE) <= 0)
-				return FALSE;
-			mail_cache_unlock_later(index->cache);
-
-			index_flags |= MAIL_INDEX_FLAG_DIRTY;
-			mail_cache_update_index_flags(index->cache, rec,
-						      index_flags);
-
-			index->header->flags |=
-				MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES;
-		}
-	}
-	return TRUE;
-}
-
-static struct mail_index_record *mbox_index_append(struct mail_index *index)
-{
-	/* update last_uid in X-IMAPbase */
-	index->header->flags |= MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES |
-		MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS;
-
-	return mail_index_append(index);
-}
-
-static time_t mbox_get_received_date(struct mail_index *index,
-				     struct mail_index_record *rec)
-{
-	time_t date;
-
-	if (mail_cache_copy_fixed_field(index->cache, rec,
-					MAIL_CACHE_RECEIVED_DATE,
-					&date, sizeof(date)))
-		return date;
-
-	mail_cache_set_corrupted(index->cache,
-		"Missing internal date for record %u", rec->uid);
-	return (time_t)-1;
-}
-
-struct mail_index mbox_index = {
-	mail_index_open,
-	mbox_index_free,
-	mbox_index_set_lock,
-	mbox_index_try_lock,
-        mail_index_set_lock_notify_callback,
-	mail_index_rebuild,
-	mail_index_fsck,
-	mbox_index_sync,
-	mail_index_get_header,
-	mail_index_lookup,
-	mail_index_next,
-        mail_index_lookup_uid_range,
-	mbox_open_mail,
-	mbox_get_received_date,
-	mbox_index_expunge,
-	mbox_index_update_flags,
-	mbox_index_append,
-	mail_index_get_last_error,
-	mail_index_get_last_error_text,
-
-	MAIL_INDEX_PRIVATE_FILL
-};
--- a/src/lib-index/mbox/mbox-index.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-#ifndef __MBOX_INDEX_H
-#define __MBOX_INDEX_H
-
-#include "md5.h"
-#include "mail-index.h"
-
-/* Extra space to leave in X-Keywords header when rewriting mbox */
-#define MBOX_HEADER_EXTRA_SPACE 100
-
-struct mbox_header_context {
-	struct mail_index *index;
-	enum mail_flags flags;
-	const char **custom_flags;
-	struct md5_context md5;
-	int received;
-
-	unsigned int uid_validity, uid_last, uid;
-
-	struct istream *input;
-	uoff_t content_length;
-};
-
-int mbox_set_syscall_error(struct mail_index *index, const char *function);
-
-/* Make sure the mbox is opened. If reopen is TRUE, the file is closed first,
-   which is useful when you want to be sure you're not accessing a deleted
-   mbox file. */
-int mbox_file_open(struct mail_index *index);
-struct istream *mbox_get_stream(struct mail_index *index,
-				enum mail_lock_type lock_type);
-void mbox_file_close_stream(struct mail_index *index);
-void mbox_file_close_fd(struct mail_index *index);
-
-void mbox_header_init_context(struct mbox_header_context *ctx,
-			      struct mail_index *index,
-			      struct istream *input);
-void mbox_header_cb(struct message_part *part,
-		    struct message_header_line *hdr, void *context);
-void mbox_keywords_parse(const unsigned char *value, size_t len,
-			 const char *custom_flags[MAIL_CUSTOM_FLAGS_COUNT],
-			 void (*func)(const unsigned char *, size_t,
-				      int, void *),
-			 void *context);
-int mbox_skip_crlf(struct istream *input);
-void mbox_skip_empty_lines(struct istream *input);
-void mbox_skip_header(struct istream *input);
-void mbox_skip_message(struct istream *input);
-int mbox_verify_end_of_body(struct istream *input, uoff_t end_offset);
-int mbox_mail_get_location(struct mail_index *index,
-			   struct mail_index_record *rec,
-			   uoff_t *offset, uoff_t *body_size);
-void mbox_read_headers(struct istream *input, buffer_t *dest);
-
-struct mail_index *
-mbox_index_alloc(const char *mbox_path, const char *index_dir,
-		 const char *control_dir);
-int mbox_index_sync(struct mail_index *index, int minimal_sync,
-		    enum mail_lock_type lock_type, int *changes);
-int mbox_sync_full(struct mail_index *index);
-struct istream *mbox_open_mail(struct mail_index *index,
-			       struct mail_index_record *rec,
-			       time_t *received_date, int *deleted);
-
-int mbox_index_append_stream(struct mail_index *index, struct istream *input);
-
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size);
-const char *mbox_from_create(const char *sender, time_t time);
-
-int mbox_index_rewrite(struct mail_index *index);
-
-struct istream *i_stream_create_mbox(pool_t pool, struct istream *input,
-				     uoff_t offset, uoff_t body_size);
-
-#endif
--- a/src/lib-index/mbox/mbox-lock.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
-#include "mail-index-util.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 mail_index *index;
-        enum mail_lock_type 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 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_spaces(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 mail_index *index,
-			   enum mail_lock_type lock_type, time_t max_wait_time)
-{
-	time_t now, last_notify;
-
-	if (lock_type == MAIL_LOCK_EXCLUSIVE)
-		lock_type = LOCK_EX;
-	else if (lock_type == MAIL_LOCK_SHARED)
-		lock_type = LOCK_SH;
-	else
-		lock_type = LOCK_UN;
-
-        last_notify = 0;
-	while (flock(index->mbox_fd, lock_type | LOCK_NB) < 0) {
-		if (errno != EWOULDBLOCK) {
-                        mbox_set_syscall_error(index, "flock()");
-			return FALSE;
-		}
-
-		if (max_wait_time == 0)
-			return FALSE;
-
-		now = time(NULL);
-		if (now >= max_wait_time) {
-			index->mailbox_lock_timeout = TRUE;
-			index_set_error(index, "Timeout while waiting for "
-					"release of flock() lock for mbox file "
-					"%s", index->mailbox_path);
-			return FALSE;
-		}
-
-		if (now != last_notify && index->lock_notify_cb != NULL) {
-			last_notify = now;
-			index->lock_notify_cb(MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
-					      max_wait_time - now,
-					      index->lock_notify_context);
-		}
-
-		usleep(LOCK_RANDOM_USLEEP_TIME);
-	}
-
-	return TRUE;
-}
-#endif
-
-static int mbox_lock_fcntl(struct mail_index *index,
-			   enum mail_lock_type lock_type, time_t max_wait_time)
-{
-	struct flock fl;
-	time_t now;
-	int wait_type;
-
-	fl.l_type = MAIL_LOCK_TO_FLOCK(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(index->mbox_fd, wait_type, &fl) < 0) {
-		if (errno != EINTR) {
-			if (errno != EAGAIN && errno != EACCES)
-				mbox_set_syscall_error(index, "fcntl()");
-			return FALSE;
-		}
-
-		now = time(NULL);
-		if (max_wait_time != 0 && now >= max_wait_time) {
-			index->mailbox_lock_timeout = TRUE;
-			index_set_error(index, "Timeout while waiting for "
-					"release of fcntl() lock for mbox file "
-					"%s", index->mailbox_path);
-			return FALSE;
-		}
-
-		if (index->lock_notify_cb != NULL) {
-			index->lock_notify_cb(MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
-					      max_wait_time - now,
-					      index->lock_notify_context);
-		}
-	}
-	return TRUE;
-}
-
-static int mbox_file_locks(struct mail_index *index,
-			   enum mail_lock_type lock_type, time_t max_wait_time)
-{
-	struct stat st;
-
-	/* now we need to have the file itself locked. open it if needed. */
-	if (stat(index->mailbox_path, &st) < 0)
-		return mbox_set_syscall_error(index, "stat()");
-
-	if (st.st_dev != index->mbox_dev || st.st_ino != index->mbox_ino)
-		mbox_file_close_fd(index);
-
-	if (index->mbox_fd == -1) {
-		if (!mbox_file_open(index)) {
-			(void)mbox_unlock(index);
-			return FALSE;
-		}
-	}
-
-	if (use_fcntl_lock && fcntl_before_flock) {
-		if (!mbox_lock_fcntl(index, lock_type, max_wait_time))
-			return FALSE;
-	}
-#ifdef HAVE_FLOCK
-	if (use_flock) {
-		if (!mbox_lock_flock(index, lock_type, max_wait_time))
-			return FALSE;
-	}
-#endif
-	if (use_fcntl_lock && !fcntl_before_flock) {
-		if (!mbox_lock_fcntl(index, lock_type, max_wait_time))
-			return FALSE;
-	}
-	return TRUE;
-}
-
-static int mbox_file_unlock(struct mail_index *index)
-{
-	int failed = FALSE;
-
-#ifdef HAVE_FLOCK
-	if (use_flock && !mbox_lock_flock(index, MAIL_LOCK_UNLOCK, 0))
-		failed = TRUE;
-#endif
-	if (use_fcntl_lock &&
-	    !mbox_lock_fcntl(index, MAIL_LOCK_UNLOCK, 0))
-		failed = TRUE;
-
-	return !failed;
-}
-
-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->index, ctx->lock_type, 0)) {
-			/* we couldn't get fcntl/flock - it's really locked */
-			ctx->last_stale = TRUE;
-			return FALSE;
-		}
-		(void)mbox_file_unlock(ctx->index);
-	}
-	ctx->last_stale = stale;
-
-	if (ctx->index->lock_notify_cb != NULL) {
-		ctx->index->lock_notify_cb(stale ?
-					   MAIL_LOCK_NOTIFY_MAILBOX_OVERRIDE :
-					   MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
-					   secs_left,
-					   ctx->index->lock_notify_context);
-	}
-	return TRUE;
-}
-
-int mbox_lock(struct mail_index *index, enum mail_lock_type lock_type)
-{
-	time_t max_wait_time;
-	int ret;
-
-	/* index must be locked before mbox file, to avoid deadlocks */
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-
-	/* allow only unlock -> shared/exclusive or exclusive -> shared */
-	i_assert(lock_type == MAIL_LOCK_SHARED ||
-		 lock_type == MAIL_LOCK_EXCLUSIVE);
-	i_assert(lock_type != MAIL_LOCK_EXCLUSIVE ||
-		 index->mbox_lock_type != MAIL_LOCK_SHARED);
-
-	if (index->mbox_lock_type == lock_type)
-		return TRUE;
-
-	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 && index->mbox_dotlock.ino == 0) {
-		struct dotlock_context ctx;
-
-		ctx.index = index;
-		ctx.lock_type = lock_type;
-		ctx.last_stale = -1;
-
-		ret = file_lock_dotlock(index->mailbox_path, NULL,
-					lock_type == MAIL_LOCK_SHARED &&
-					!use_read_dotlock, lock_timeout,
-					dotlock_change_timeout, 0,
-					dotlock_callback, &ctx,
-					&index->mbox_dotlock);
-
-		if (ret < 0) {
-			mbox_set_syscall_error(index, "file_lock_dotlock()");
-			return FALSE;
-		}
-		if (ret == 0) {
-			index_set_error(index, "Timeout while waiting for "
-					"release of dotlock for mbox %s",
-					index->mailbox_path);
-			index->mailbox_lock_timeout = TRUE;
-			return FALSE;
-		}
-	}
-
-	index->mbox_lock_type = lock_type;
-	if (!mbox_file_locks(index, index->mbox_lock_type, max_wait_time)) {
-		(void)mbox_unlock(index);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-int mbox_unlock(struct mail_index *index)
-{
-	int failed;
-
-	index->mbox_lock_counter++;
-
-	if (index->mbox_lock_type == MAIL_LOCK_UNLOCK)
-		return TRUE;
-
-	failed = FALSE;
-	if (index->mbox_fd != -1) {
-		if (!mbox_file_unlock(index))
-			failed = TRUE;
-	}
-
-	if (index->mbox_dotlock.ino != 0) {
-		if (file_unlock_dotlock(index->mailbox_path,
-					&index->mbox_dotlock) <= 0) {
-                        mbox_set_syscall_error(index, "file_unlock_dotlock()");
-			failed = TRUE;
-		}
-                index->mbox_dotlock.ino = 0;
-	}
-
-	/* make sure we don't keep mmap() between locks - there could have
-	   been changes to file size which would break things. or actually
-	   it'd break only if file was shrinked+grown back to exact size,
-	   but still possible :) */
-	mbox_file_close_stream(index);
-
-	index->mbox_lock_type = MAIL_LOCK_UNLOCK;
-	return !failed;
-}
--- a/src/lib-index/mbox/mbox-lock.h	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-#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 mail_index *index, enum mail_lock_type lock_type);
-int mbox_unlock(struct mail_index *index);
-
-#endif
--- a/src/lib-index/mbox/mbox-open.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "istream.h"
-#include "mbox-index.h"
-#include "mail-index-util.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-struct istream *mbox_open_mail(struct mail_index *index,
-			       struct mail_index_record *rec,
-			       time_t *received_date, int *deleted)
-{
-	struct istream *input;
-	uoff_t offset, body_size;
-
-	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
-
-	*deleted = FALSE;
-
-	/* check for inconsistency here, to avoid extra error messages */
-	if (index->inconsistent)
-		return NULL;
-
-	if (!mbox_mail_get_location(index, rec, &offset, &body_size))
-		return NULL;
-
-	input = mbox_get_stream(index, MAIL_LOCK_SHARED);
-	if (input == NULL)
-		return NULL;
-
-	if (received_date != NULL)
-		*received_date = index->get_received_date(index, rec);
-
-	i_assert(index->mbox_sync_counter == index->mbox_lock_counter);
-	return i_stream_create_mbox(default_pool, input, offset, body_size);
-}
--- a/src/lib-index/mbox/mbox-rewrite.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,791 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "istream.h"
-#include "ostream.h"
-#include "file-set-size.h"
-#include "str.h"
-#include "write-full.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
-#include "mail-index-util.h"
-#include "mail-custom-flags.h"
-#include "mail-cache.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-struct mbox_rewrite_context {
-	struct ostream *output;
-
-	uoff_t content_length;
-	unsigned int seq, uid;
-	unsigned int msg_flags;
-	const char **custom_flags;
-
-	unsigned int uid_validity;
-	unsigned int uid_last;
-	char *x_keywords;
-
-	unsigned int ximapbase_found:1;
-	unsigned int xuid_found:1;
-	unsigned int status_found:1;
-	unsigned int xstatus_found:1;
-	unsigned int content_length_found:1;
-};
-
-/* Remove dirty flag from all messages */
-static int reset_dirty_flags(struct mail_index *index)
-{
-	struct mail_index_record *rec;
-	enum mail_index_record_flag index_flags;
-
-	if (mail_cache_lock(index->cache, FALSE) <= 0)
-		return FALSE;
-	mail_cache_unlock_later(index->cache);
-
-	rec = index->lookup(index, 1);
-	while (rec != NULL) {
-		index_flags = mail_cache_get_index_flags(index->cache, rec);
-		if ((index_flags & MAIL_INDEX_FLAG_DIRTY) != 0) {
-			index_flags &= ~MAIL_INDEX_FLAG_DIRTY;
-			if (!mail_cache_update_index_flags(index->cache,
-							   rec, index_flags))
-				return FALSE;
-		}
-
-		rec = index->next(index, rec);
-	}
-
-	index->header->flags &= ~(MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES |
-				  MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS);
-	return TRUE;
-}
-
-static int mbox_write(struct mail_index *index, struct istream *input,
-		      struct ostream *output, uoff_t end_offset)
-{
-	int failed;
-
-	i_assert(input->v_offset <= end_offset);
-
-	input = i_stream_create_limit(default_pool, input, 0, end_offset);
-	if (o_stream_send_istream(output, input) < 0) {
-		index_set_error(index, "Error rewriting mbox file %s: %s",
-				index->mailbox_path,
-				strerror(output->stream_errno));
-		failed = TRUE;
-	} else if (input->v_offset < end_offset) {
-		/* sync should have noticed it.. */
-		index_set_error(index, "Error rewriting mbox file %s: "
-				"Unexpected end of file", index->mailbox_path);
-		failed = TRUE;
-	} else {
-		failed = FALSE;
-	}
-
-	i_stream_unref(input);
-	return !failed;
-}
-
-static int mbox_write_ximapbase(struct mbox_rewrite_context *ctx)
-{
-	const char *str;
-	int i;
-
-	str = t_strdup_printf("X-IMAPbase: %u %u",
-			      ctx->uid_validity, ctx->uid_last);
-	if (o_stream_send_str(ctx->output, str) < 0)
-		return FALSE;
-
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
-		if (ctx->custom_flags[i] != NULL) {
-			if (o_stream_send(ctx->output, " ", 1) < 0)
-				return FALSE;
-
-			if (o_stream_send_str(ctx->output,
-					      ctx->custom_flags[i]) < 0)
-				return FALSE;
-		}
-	}
-
-	if (o_stream_send(ctx->output, "\n", 1) < 0)
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mbox_write_xuid(struct mbox_rewrite_context *ctx)
-{
-	const char *str;
-
-	str = t_strdup_printf("X-UID: %u\n", ctx->uid);
-
-	if (o_stream_send_str(ctx->output, str) < 0)
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mbox_write_xkeywords(struct mbox_rewrite_context *ctx,
-				const char *x_keywords, uoff_t wanted_offset,
-				int force_filler)
-{
-	unsigned int field;
-	int i;
-
-	if ((ctx->msg_flags & MAIL_CUSTOM_FLAGS_MASK) == 0 &&
-	    x_keywords == NULL && !force_filler &&
-	    ctx->output->offset + sizeof("X-Keywords:")+1 >= wanted_offset) {
-		/* nothing to do, and not enough extra space to write the
-		   filler. Do it only if there's space for "X-Keywords: \n" */
-		return TRUE;
-	}
-
-	if (o_stream_send_str(ctx->output, "X-Keywords:") < 0)
-		return FALSE;
-
-	field = 1 << MAIL_CUSTOM_FLAG_1_BIT;
-	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++, field <<= 1) {
-		if ((ctx->msg_flags & field) && ctx->custom_flags[i] != NULL) {
-			if (o_stream_send(ctx->output, " ", 1) < 0)
-				return FALSE;
-
-			if (o_stream_send_str(ctx->output,
-					      ctx->custom_flags[i]) < 0)
-				return FALSE;
-		}
-	}
-
-	if (x_keywords != NULL) {
-		/* X-Keywords that aren't custom flags */
-		if (o_stream_send(ctx->output, " ", 1) < 0)
-			return FALSE;
-
-		if (o_stream_send_str(ctx->output, x_keywords) < 0)
-			return FALSE;
-	}
-
-	/* fill the rest with spaces. -1 for \n */
-	if (ctx->output->offset < wanted_offset-1 || force_filler) {
-		char buf[1024];
-		uoff_t fill_left;
-
-		fill_left = force_filler ? MBOX_HEADER_EXTRA_SPACE :
-			wanted_offset-1 - ctx->output->offset;
-		memset(buf, ' ', sizeof(buf));
-		while (fill_left > sizeof(buf)) {
-			if (o_stream_send(ctx->output, buf, sizeof(buf)) < 0)
-				return FALSE;
-			fill_left -= sizeof(buf);
-		}
-		if (o_stream_send(ctx->output, buf, fill_left) < 0)
-			return FALSE;
-	}
-
-	if (o_stream_send(ctx->output, "\n", 1) < 0)
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mbox_write_status(struct mbox_rewrite_context *ctx,
-			     const char *status)
-{
-	const char *str;
-
-	str = (ctx->msg_flags & MAIL_SEEN) ? "Status: RO" : "Status: O";
-	if (status != NULL)
-		str = t_strconcat(str, status, NULL);
-
-	if (o_stream_send_str(ctx->output, str) < 0)
-		return FALSE;
-	if (o_stream_send(ctx->output, "\n", 1) < 0)
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mbox_write_xstatus(struct mbox_rewrite_context *ctx,
-			      const char *x_status)
-{
-	const char *str;
-
-	/* X-Status field */
-	if ((ctx->msg_flags & (MAIL_SYSTEM_FLAGS_MASK^MAIL_SEEN)) == 0 &&
-	    x_status == NULL)
-		return TRUE;
-
-	str = t_strconcat("X-Status: ",
-			  (ctx->msg_flags & MAIL_ANSWERED) ? "A" : "",
-			  (ctx->msg_flags & MAIL_DELETED) ? "D" : "",
-			  (ctx->msg_flags & MAIL_FLAGGED) ? "F" : "",
-			  (ctx->msg_flags & MAIL_DRAFT) ? "T" : "",
-			  x_status, NULL);
-
-	if (o_stream_send_str(ctx->output, str) < 0)
-		return FALSE;
-	if (o_stream_send(ctx->output, "\n", 1) < 0)
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mbox_write_content_length(struct mbox_rewrite_context *ctx)
-{
-	char str[MAX_INT_STRLEN+30];
-
-	i_snprintf(str, sizeof(str), "Content-Length: %"PRIuUOFF_T"\n",
-		   ctx->content_length);
-
-	if (o_stream_send_str(ctx->output, str) < 0)
-		return FALSE;
-	return TRUE;
-}
-
-static const char *strip_chars(const unsigned char *value, size_t value_len,
-			       const char *list)
-{
-	/* @UNSAFE: leave only unknown flags, very likely none */
-	char *ret, *p;
-	size_t i;
-
-	ret = p = t_buffer_get(value_len+1);
-	for (i = 0; i < value_len; i++) {
-		if (strchr(list, value[i]) == NULL)
-			*p++ = value[i];
-	}
-
-	if (ret == p)
-		return NULL;
-	*p = '\0';
-        t_buffer_alloc((size_t) (p-ret)+1);
-	return ret;
-}
-
-static void update_stripped_custom_flags(const unsigned char *value, size_t len,
-					 int index, void *context)
-{
-	string_t *str = context;
-
-	if (index < 0) {
-		/* not found, keep it */
-		if (str_len(str) != 0)
-			str_append_c(str, ' ');
-		str_append_n(str, value, len);
-	}
-}
-
-static const char *strip_custom_flags(const unsigned char *value, size_t len,
-				      struct mbox_rewrite_context *ctx)
-{
-	string_t *str;
-
-	str = t_str_new(len+1);
-	mbox_keywords_parse(value, len, ctx->custom_flags,
-			    update_stripped_custom_flags, str);
-	return str_len(str) == 0 ? NULL : str_c(str);
-}
-
-static int write_header(struct mbox_rewrite_context *ctx,
-			struct message_header_line *hdr)
-{
-	const char *str;
-
-	switch (hdr->name_len) {
-	case 5:
-		if (strcasecmp(hdr->name, "X-UID") == 0) {
-			if (ctx->xuid_found)
-				return TRUE;
-
-			ctx->xuid_found = TRUE;
-			return mbox_write_xuid(ctx);
-		}
-		break;
-	case 6:
-		if (strcasecmp(hdr->name, "Status") == 0) {
-			if (ctx->status_found)
-				return TRUE;
-			if (hdr->continues) {
-				hdr->use_full_value = TRUE;
-				return TRUE;
-			}
-
-			ctx->status_found = TRUE;
-			str = strip_chars(hdr->full_value,
-					  hdr->full_value_len, "RO");
-			return mbox_write_status(ctx, str);
-		}
-		break;
-	case 8:
-		if (strcasecmp(hdr->name, "X-Status") == 0) {
-			if (ctx->xstatus_found)
-				return TRUE;
-			if (hdr->continues) {
-				hdr->use_full_value = TRUE;
-				return TRUE;
-			}
-
-			ctx->xstatus_found = TRUE;
-			str = strip_chars(hdr->full_value,
-					  hdr->full_value_len, "ADFT");
-			return mbox_write_xstatus(ctx, str);
-		}
-		break;
-	case 10:
-		if (strcasecmp(hdr->name, "X-Keywords") == 0) {
-			if (ctx->x_keywords != NULL)
-				return TRUE;
-			if (hdr->continues) {
-				hdr->use_full_value = TRUE;
-				return TRUE;
-			}
-
-			str = strip_custom_flags(hdr->full_value,
-						 hdr->full_value_len, ctx);
-			ctx->x_keywords = i_strdup(str);
-			return TRUE;
-		} else if (strcasecmp(hdr->name, "X-IMAPbase") == 0) {
-			if (ctx->seq != 1 || ctx->ximapbase_found)
-				return TRUE;
-
-			ctx->ximapbase_found = TRUE;
-			return mbox_write_ximapbase(ctx);
-		}
-		break;
-	case 14:
-		if (strcasecmp(hdr->name, "Content-Length") == 0) {
-			if (ctx->content_length_found)
-				return TRUE;
-
-			ctx->content_length_found = TRUE;
-			return mbox_write_content_length(ctx);
-		}
-		break;
-	}
-
-	if (!hdr->eoh) {
-		/* save this header */
-		if (!hdr->continued) {
-			(void)o_stream_send(ctx->output, hdr->name,
-					    hdr->name_len);
-			(void)o_stream_send(ctx->output, ": ", 2);
-		}
-		(void)o_stream_send(ctx->output, hdr->value, hdr->value_len);
-		if (!hdr->no_newline)
-			(void)o_stream_send(ctx->output, "\n", 1);
-	}
-
-	return !ctx->output->closed;
-}
-
-static int mbox_write_header(struct mail_index *index,
-			     struct mail_index_record *rec, unsigned int seq,
-			     struct istream *input, struct ostream *output,
-			     uoff_t dirty_offset,
-			     uoff_t *hdr_input_size, uoff_t body_size)
-{
-	/* We need to update fields that define message flags. Standard fields
-	   are stored in Status and X-Status. For custom flags we use
-	   uw-imapd compatible format, by first listing them in first message's
-	   X-IMAPbase field and actually defining them in X-Keywords field.
-
-	   Format of X-IMAPbase is: <UID validity> <last used UID> <flag names>
-
-	   We don't want to sync our UIDs with the mbox file, so the UID
-	   validity is always kept different from our internal UID validity.
-	   Last used UID is also not updated, and set to 0 initially.
-	*/
-	struct mbox_rewrite_context ctx;
-	struct message_header_parser_ctx *hdr_ctx;
-	struct message_header_line *hdr;
-	struct message_size hdr_size;
-	struct istream *hdr_input;
-	uoff_t offset;
-	int force_filler;
-
-	t_push();
-
-	/* parse the header, write the fields we don't want to change */
-	memset(&ctx, 0, sizeof(ctx));
-	ctx.output = output;
-	ctx.content_length = body_size;
-	ctx.seq = seq;
-	ctx.uid = rec->uid;
-	ctx.msg_flags = rec->msg_flags;
-	ctx.uid_validity = index->header->uid_validity;
-	ctx.uid_last = index->header->next_uid-1;
-	ctx.custom_flags = mail_custom_flags_list_get(index->custom_flags);
-
-	if (body_size != 0) {
-		hdr_input = input;
-		i_stream_ref(hdr_input);
-	} else {
-		/* possibly broken message, find the next From-line
-		   and make sure header parser won't pass it. */
-		offset = input->v_offset;
-		mbox_skip_header(input);
-		i_stream_seek(input, offset);
-		hdr_input = i_stream_create_limit(default_pool, input, 0,
-						  input->v_offset);
-	} 
-
-	hdr_ctx = message_parse_header_init(hdr_input, &hdr_size);
-	while ((hdr = message_parse_header_next(hdr_ctx)) != NULL) {
-		t_push();
-		write_header(&ctx, hdr);
-		t_pop();
-	}
-	message_parse_header_deinit(hdr_ctx);
-	*hdr_input_size = hdr_size.physical_size;
-
-	i_stream_unref(hdr_input);
-
-	/* append the flag fields */
-	if (seq == 1 && !ctx.ximapbase_found) {
-		/* write X-IMAPbase header to first message */
-		(void)mbox_write_ximapbase(&ctx);
-	}
-
-	force_filler = !ctx.xuid_found;
-	if (!ctx.status_found)
-		(void)mbox_write_status(&ctx, NULL);
-	if (!ctx.xstatus_found)
-		(void)mbox_write_xstatus(&ctx, NULL);
-	if (!ctx.xuid_found)
-		(void)mbox_write_xuid(&ctx);
-	if (!ctx.content_length_found)
-		(void)mbox_write_content_length(&ctx);
-
-	/* write the x-keywords header last so it can fill the extra space
-	   with spaces. -1 is for ending \n. */
-	(void)mbox_write_xkeywords(&ctx, ctx.x_keywords,
-				   input->v_offset - dirty_offset - 1,
-				   force_filler);
-	i_free(ctx.x_keywords);
-
-	t_pop();
-
-	/* empty line ends headers */
-	(void)o_stream_send(output, "\n", 1);
-
-	return TRUE;
-}
-
-static int fd_copy(struct mail_index *index, int in_fd, int out_fd,
-		   uoff_t out_offset, uoff_t size)
-{
-	struct istream *input, *input2;
-	struct ostream *output;
-	struct stat st;
-	int ret;
-
-	i_assert(out_offset <= OFF_T_MAX);
-
-	/* first grow the file to wanted size, to make sure we don't run out
-	   of disk space */
-	if (fstat(out_fd, &st) < 0) {
-		mbox_set_syscall_error(index, "fstat()");
-		return -1;
-	}
-
-	if ((uoff_t)st.st_size < out_offset + size) {
-		if (file_set_size(out_fd, (off_t)(out_offset + size)) < 0) {
-			mbox_set_syscall_error(index, "file_set_size()");
-			(void)ftruncate(out_fd, st.st_size);
-			return -1;
-		}
-	}
-
-	if (lseek(out_fd, (off_t)out_offset, SEEK_SET) < 0) {
-		mbox_set_syscall_error(index, "lseek()");
-		(void)ftruncate(out_fd, st.st_size);
-		return -1;
-	}
-
-	t_push();
-
-	input = i_stream_create_file(in_fd, pool_datastack_create(),
-				     1024*256, FALSE);
-	input2 = i_stream_create_limit(pool_datastack_create(), input, 0, size);
-
-	output = o_stream_create_file(out_fd, pool_datastack_create(),
-				      1024, FALSE);
-	o_stream_set_blocking(output, 60000, NULL, NULL);
-
-	ret = o_stream_send_istream(output, input2);
-	if (ret < 0) {
-		errno = output->stream_errno;
-		mbox_set_syscall_error(index, "o_stream_send_istream()");
-	}
-
-	o_stream_unref(output);
-	i_stream_unref(input2);
-	i_stream_unref(input);
-	t_pop();
-
-	return ret;
-}
-
-static int dirty_flush(struct mail_index *index, uoff_t dirty_offset,
-		       struct ostream *output, int output_fd)
-{
-	if (output->offset == 0)
-		return TRUE;
-
-	if (o_stream_flush(output) < 0) {
-		mbox_set_syscall_error(index, "o_stream_flush()");
-		return FALSE;
-	}
-
-	/* POSSIBLE DATA LOSS HERE. We're writing to the mbox file,
-	   so if we get killed here before finished, we'll lose some
-	   bytes. I can't really think of any way to fix this,
-	   rename() is problematic too especially because of file
-	   locking issues (new mail could be lost).
-
-	   Usually we're moving the data by just a few bytes, so
-	   the data loss should never be more than those few bytes..
-	   If we moved more, we could have written the file from end
-	   to beginning in blocks (it'd be a bit slow to do it in
-	   blocks of ~1-10 bytes which is the usual case, so we don't
-	   bother).
-
-	   Also, we might as well be shrinking the file, in which
-	   case we can't lose data. */
-	if (fd_copy(index, output_fd, index->mbox_fd,
-		    dirty_offset, output->offset) < 0)
-		return FALSE;
-
-	/* All ok. Just make sure the timestamps of index and
-	   mbox differ, so index will be updated at next sync */
-	index->sync_stamp = 0;
-
-	if (o_stream_seek(output, 0) < 0) {
-		mbox_set_syscall_error(index, "o_stream_seek()");
-		return FALSE;
-	}
-	return TRUE;
-}
-
-#define INDEX_DIRTY_FLAGS \
-	(MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES | \
-	 MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS)
-
-int mbox_index_rewrite(struct mail_index *index)
-{
-	/* Write messages beginning from the first dirty one to temp file,
-	   then copy it over the mbox file. This may create data loss if
-	   interrupted (see below). This rewriting relies quite a lot on
-	   valid header/body sizes which fsck() should have ensured. */
-	struct mail_index_record *rec;
-	struct istream *input;
-	struct ostream *output;
-	uoff_t offset, hdr_size, body_size, dirty_offset;
-	const char *path;
-	unsigned int seq;
-	int tmp_fd, failed, dirty, dirty_found, rewrite, no_locking;
-
-	i_assert(!index->mailbox_readonly);
-	i_assert(index->lock_type == MAIL_LOCK_UNLOCK ||
-		 (index->lock_type == MAIL_LOCK_EXCLUSIVE &&
-		  index->mbox_lock_type == MAIL_LOCK_EXCLUSIVE));
-
-	no_locking = index->mbox_lock_type == MAIL_LOCK_EXCLUSIVE;
-	if (!no_locking) {
-		if (!index->set_lock(index, MAIL_LOCK_SHARED))
-			return FALSE;
-	}
-
-	rewrite = (index->header->flags & INDEX_DIRTY_FLAGS) &&
-		index->header->messages_count > 0;
-
-	if (!no_locking) {
-		if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-			return FALSE;
-	}
-
-	if (!rewrite) {
-		/* no need to rewrite */
-		return TRUE;
-	}
-
-	/* kludgy .. but we need to force resyncing */
-	index->mbox_rewritten = TRUE;
-
-	tmp_fd = -1; input = NULL;
-	failed = TRUE; rewrite = FALSE;
-	do {
-		if (!no_locking) {
-			if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-				break;
-
-			if (!index->sync_and_lock(index, FALSE,
-						  MAIL_LOCK_EXCLUSIVE, NULL))
-				break;
-		}
-
-		input = mbox_get_stream(index, MAIL_LOCK_EXCLUSIVE);
-		if (input == NULL)
-			break;
-
-		if ((index->header->flags & INDEX_DIRTY_FLAGS) == 0) {
-			/* fsck() figured out there's no dirty messages
-			   after all */
-			failed = FALSE; rewrite = FALSE;
-			break;
-		}
-
-		tmp_fd = mail_index_create_temp_file(index, &path);
-		if (tmp_fd == -1)
-			break;
-
-		failed = FALSE; rewrite = TRUE;
-	} while (0);
-
-	if (!rewrite) {
-		if (!no_locking) {
-			if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-				failed = TRUE;
-		}
-		if (input != NULL)
-			i_stream_unref(input);
-		return !failed;
-	}
-
-	if (index->header->flags & MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS) {
-		/* need to update X-IMAPbase in first message */
-		dirty_found = TRUE;
-	} else {
-		dirty_found = FALSE;
-	}
-	dirty_offset = 0;
-
-	/* note: we can't use data_stack_pool with output stream because it's
-	   being written to inside t_push() .. t_pop() calls */
-	output = o_stream_create_file(tmp_fd, system_pool, 8192, FALSE);
-	o_stream_set_blocking(output, 60000, NULL, NULL);
-
-	failed = FALSE; seq = 1;
-	rec = index->lookup(index, 1);
-	while (rec != NULL) {
-		if (dirty_found)
-			dirty = FALSE;
-		else {
-			dirty = (mail_cache_get_index_flags(index->cache, rec) &
-				 MAIL_INDEX_FLAG_DIRTY) != 0;
-		}
-
-		if (dirty_found || dirty) {
-			/* get offset to beginning of mail headers */
-			if (!mbox_mail_get_location(index, rec, &offset,
-						    &body_size)) {
-				/* fsck should have fixed it */
-				failed = TRUE;
-				break;
-			}
-
-			if (offset < input->v_offset) {
-				mail_cache_set_corrupted(index->cache,
-					"Invalid message offset");
-				failed = TRUE;
-				break;
-			}
-
-			if (!dirty_found) {
-				/* first dirty message */
-				dirty_found = TRUE;
-				dirty_offset = offset;
-
-				i_stream_seek(input, dirty_offset);
-			}
-
-			/* write the From-line */
-			if (!mbox_write(index, input, output, offset)) {
-				failed = TRUE;
-				break;
-			}
-
-			/* write header, updating flag fields */
-			if (!mbox_write_header(index, rec, seq, input, output,
-					       dirty_offset,
-					       &hdr_size, body_size)) {
-				failed = TRUE;
-				break;
-			}
-			offset += hdr_size;
-			i_assert(input->v_offset == offset);
-
-			if (dirty_found &&
-			    offset - dirty_offset == output->offset) {
-				/* no need to write more, flush */
-				if (!dirty_flush(index, dirty_offset,
-						 output, tmp_fd)) {
-					failed = TRUE;
-					break;
-				}
-				dirty_found = FALSE;
-			} else {
-				/* write body */
-				offset += body_size;
-				if (!mbox_write(index, input, output, offset)) {
-					failed = TRUE;
-					break;
-				}
-			}
-		}
-
-		seq++;
-		rec = index->next(index, rec);
-	}
-
-	if (!failed && dirty_found) {
-		/* end with \n */
-		(void)o_stream_send(output, "\n", 1);
-	}
-
-	if (output->closed) {
-		errno = output->stream_errno;
-		mbox_set_syscall_error(index, "write()");
-		failed = TRUE;
-	}
-
-	if (!failed && dirty_found) {
-		uoff_t dirty_size = output->offset;
-
-		if (!dirty_flush(index, dirty_offset, output, tmp_fd))
-			failed = TRUE;
-		else {
-			/* we may have shrinked the file */
-			i_assert(dirty_offset + dirty_size <= OFF_T_MAX);
-			if (ftruncate(index->mbox_fd,
-				      (off_t)(dirty_offset + dirty_size)) < 0) {
-				mbox_set_syscall_error(index, "ftruncate()");
-				failed = TRUE;
-			}
-		}
-	}
-
-	if (!failed) {
-		if (!reset_dirty_flags(index))
-			failed = TRUE;
-	}
-
-	i_stream_unref(input);
-	o_stream_unref(output);
-
-	if (!no_locking) {
-		if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-			failed = TRUE;
-	}
-
-	(void)unlink(path);
-
-	if (close(tmp_fd) < 0)
-		index_file_set_syscall_error(index, path, "close()");
-	return !failed;
-}
--- a/src/lib-index/mbox/mbox-sync-full.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,349 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "istream.h"
-#include "hex-binary.h"
-#include "message-parser.h"
-#include "message-part-serialize.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
-#include "mail-index-util.h"
-#include "mail-cache.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-static void skip_line(struct istream *input)
-{
-	const unsigned char *msg;
-	size_t i, size;
-	int ret;
-
-	while ((ret = i_stream_read_data(input, &msg, &size, 0)) > 0) {
-		for (i = 0; i < size; i++) {
-			if (msg[i] == '\n') {
-				i_stream_skip(input, i+1);
-				return;
-			}
-		}
-
-		i_stream_skip(input, i);
-	}
-}
-
-static int verify_header(struct mail_index *index,
-			 struct mail_index_record *rec,
-			 unsigned int uid, unsigned char current_digest[16])
-{
-	const void *old_digest;
-	size_t size;
-
-	if (uid != 0) {
-		/* X-UID header - no need to check more */
-		return uid == rec->uid;
-	}
-
-	/* check if MD5 sums match */
-	if (!mail_cache_lookup_field(index->cache, rec, MAIL_CACHE_MD5,
-				     &old_digest, &size))
-		return FALSE;
-
-	return memcmp(old_digest, current_digest, 16) == 0;
-}
-
-static int mbox_check_uidvalidity(struct mail_index *index,
-				  unsigned int uid_validity)
-{
-	if (uid_validity == index->header->uid_validity)
-		return TRUE;
-
-	index->header->flags |= MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES |
-		MAIL_INDEX_HDR_FLAG_DIRTY_CUSTOMFLAGS;
-
-	if (uid_validity == 0) {
-		/* X-IMAPbase header isn't written yet */
-	} else {
-		/* UID validity has changed - rebuild whole index */
-		index->set_flags |= MAIL_INDEX_HDR_FLAG_REBUILD;
-		index->inconsistent = TRUE;
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static int match_next_record(struct mail_index *index,
-			     struct mail_index_record *rec,
-			     unsigned int *seq, struct istream *input,
-			     struct mail_index_record **next_rec, int *dirty)
-{
-	struct mbox_header_context ctx;
-	struct mail_index_record *first_rec, *last_rec;
-	struct istream *hdr_input;
-        enum mail_index_record_flag index_flags;
-	uoff_t header_offset, body_offset, offset, body_size, eoh_offset;
-	unsigned char current_digest[16];
-	unsigned int first_seq, last_seq;
-	int ret, hdr_parsed;
-
-	*next_rec = NULL;
-
-	/* skip the From-line */
-	skip_line(input);
-	header_offset = input->v_offset;
-
-	first_rec = last_rec = NULL;
-	first_seq = last_seq = 0;
-	ret = 0; body_offset = 0; eoh_offset = (uoff_t)-1; hdr_parsed = FALSE;
-	do {
-		if (!mbox_mail_get_location(index, rec, &offset, &body_size))
-			return -1;
-
-		if (body_size == 0 && eoh_offset == (uoff_t)-1) {
-			/* possibly broken message, find the next From-line
-			   and make sure header parser won't pass it. */
-			i_stream_seek(input, header_offset);
-			mbox_skip_header(input);
-			eoh_offset = input->v_offset;
-			hdr_parsed = FALSE;
-		}
-
-		if (!hdr_parsed) {
-			/* get the MD5 sum of fixed headers and the current
-			   message flags in Status and X-Status fields */
-			if (eoh_offset == (uoff_t)-1)
-				hdr_input = input;
-			else {
-				hdr_input = i_stream_create_limit(default_pool,
-						input, 0, eoh_offset);
-			}
-			i_stream_seek(hdr_input, header_offset);
-
-			mbox_header_init_context(&ctx, index, hdr_input);
-			message_parse_header(NULL, hdr_input, NULL,
-					     mbox_header_cb, &ctx);
-
-			hdr_parsed = TRUE;
-			body_offset = hdr_input->v_offset;
-
-			if (eoh_offset != (uoff_t)-1)
-				i_stream_unref(hdr_input);
-			hdr_input = NULL;
-			md5_final(&ctx.md5, current_digest);
-
-			if (*seq == 1) {
-				if (!mbox_check_uidvalidity(index,
-							    ctx.uid_validity)) {
-					/* uidvalidity changed, abort */
-					return -1;
-				}
-
-				if (ctx.uid_last >= index->header->next_uid) {
-					/* last_uid larger than ours */
-					index->header->next_uid =
-						ctx.uid_last+1;
-				}
-			}
-		}
-
-		if (verify_header(index, rec, ctx.uid, current_digest) &&
-		    mbox_verify_end_of_body(input, body_offset + body_size)) {
-			/* valid message */
-
-			/* update flags, unless we've changed them */
-			index_flags =
-				mail_cache_get_index_flags(index->cache, rec);
-			if ((index_flags & MAIL_INDEX_FLAG_DIRTY) == 0) {
-				if (!index->update_flags(index, rec, *seq,
-							 MODIFY_REPLACE,
-							 ctx.flags, TRUE))
-					return -1;
-			} else if (rec->msg_flags == ctx.flags) {
-				/* flags are same, it's not dirty anymore */
-				index_flags &= ~MAIL_INDEX_FLAG_DIRTY;
-				mail_cache_update_index_flags(index->cache,
-							      rec, index_flags);
-			} else {
-				*dirty = TRUE;
-			}
-
-			/* update location */
-			if (offset != header_offset) {
-				if (!mail_cache_update_location_offset(
-					index->cache, rec, header_offset))
-					return -1;
-			}
-			ret = 1;
-			break;
-		}
-
-		/* try next message */
-		if (first_rec == NULL) {
-			first_rec = rec;
-			first_seq = *seq;
-		}
-		last_rec = rec;
-		last_seq = *seq;
-
-		rec = index->next(index, rec); *seq += 1;
-	} while (rec != NULL);
-
-	if (first_rec == NULL) {
-		*seq += 1;
-		*next_rec = rec == NULL ? NULL : index->next(index, rec);
-	} else {
-		if (!index->expunge(index, first_rec, last_rec,
-				    first_seq, last_seq, TRUE))
-			return -1;
-
-		*seq = first_seq + 1;
-		*next_rec = index->lookup(index, *seq);
-	}
-
-	return ret;
-}
-
-static int mbox_sync_from_stream(struct mail_index *index,
-				 struct istream *input)
-{
-	struct mail_index_record *rec;
-	uoff_t from_offset;
-	const unsigned char *data;
-	size_t size;
-	unsigned int seq;
-	int dirty, ret;
-
-	if (mail_cache_lock(index->cache, FALSE) <= 0)
-		return -1;
-	mail_cache_unlock_later(index->cache);
-
-	mbox_skip_empty_lines(input);
-
-	/* first make sure we start with a "From " line. If file is too
-	   small, we'll just treat it as empty mbox file. */
-	if (i_stream_read_data(input, &data, &size, 5) > 0 &&
-	    memcmp(data, "From ", 5) != 0) {
-		index_set_error(index, "File isn't in mbox format: %s",
-				index->mailbox_path);
-		return -1;
-	}
-
-	/* we'll go through the mailbox and index in order matching the
-	   messages by their size and Message-ID. old mails aren't remembered,
-	   so we handle well only the cases when mail has been deleted. if
-	   mails have been reordered (eg. sorted by someone) most of the mails
-	   will show up as being new. if we really wanted to support that well,
-	   we could save the message-ids into hash but I don't know if it's
-	   worth the trouble. */
-
-	seq = 1;
-	rec = index->lookup(index, 1);
-
-	dirty = FALSE;
-	while (rec != NULL) {
-		from_offset = input->v_offset;
-		if (input->v_offset != 0) {
-			/* we're at the [\r]\n before the From-line,
-			   skip it */
-			if (!mbox_skip_crlf(input)) {
-				/* they just went and broke it, even while
-				   we had it locked. */
-				index_set_error(index,
-						"Error syncing mbox file %s: "
-						"LF not found where expected",
-						index->mailbox_path);
-				return -1;
-			}
-		}
-
-		ret = match_next_record(index, rec, &seq, input, &rec, &dirty);
-		if (ret < 0)
-			return -1;
-
-		if (ret == 0) {
-			/* Get back to line before From */
-			i_stream_seek(input, from_offset);
-		}
-	}
-
-	/* delete the rest of the records */
-	if (rec != NULL) {
-		if (!index->expunge(index, rec, INDEX_END_RECORD(index)-1,
-				    seq, index->header->messages_count, TRUE))
-			return -1;
-	}
-
-	if (!dirty &&
-	    (index->header->flags & MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES)) {
-		/* no flags are dirty anymore, no need to rewrite */
-		index->header->flags &= ~MAIL_INDEX_HDR_FLAG_DIRTY_MESSAGES;
-	}
-
-	if ((index->set_flags & MAIL_INDEX_HDR_FLAG_REBUILD))
-		return 1;
-	else
-		return mbox_index_append_stream(index, input);
-}
-
-int mbox_sync_full(struct mail_index *index)
-{
-	struct istream *input;
-	struct stat orig_st, st;
-	uoff_t continue_offset;
-	int ret, failed;
-
-	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-	input = mbox_get_stream(index, MAIL_LOCK_SHARED);
-	if (input == NULL)
-		return FALSE;
-
-	if (fstat(index->mbox_fd, &orig_st) < 0) {
-		mbox_set_syscall_error(index, "fstat()");
-		continue_offset = (uoff_t)-1;
-		failed = TRUE;
-	} else {
-		ret = mbox_sync_from_stream(index, input);
-		failed = ret < 0;
-		continue_offset = ret != 0 ||
-			(index->set_flags & MAIL_INDEX_HDR_FLAG_REBUILD) ?
-			(uoff_t)-1 : input->v_offset;
-		i_stream_unref(input);
-	}
-
-	if (continue_offset != (uoff_t)-1) {
-		/* mbox_index_append() stopped, which means that it wants
-		   write access to mbox. if mbox hasn't changed after
-		   unlock+lock, we should be able to safely continue where we
-		   were left off last time. otherwise do full resync. */
-		if (!mbox_unlock(index))
-			return FALSE;
-
-		input = mbox_get_stream(index, MAIL_LOCK_EXCLUSIVE);
-		if (input == NULL)
-			return FALSE;
-
-		if (fstat(index->mbox_fd, &st) < 0) {
-			mbox_set_syscall_error(index, "fstat()");
-			failed = TRUE;
-		} else if (st.st_mtime == orig_st.st_mtime &&
-			   st.st_size == orig_st.st_size) {
-			i_stream_seek(input, continue_offset);
-			failed = mbox_index_append_stream(index, input) <= 0;
-		} else {
-			failed = mbox_sync_from_stream(index, input) <= 0;
-		}
-
-		if (index->mbox_rewritten) {
-			/* rewritten, sync again */
-                        index->mbox_rewritten = FALSE;
-			i_stream_seek(input, 0);
-			failed = mbox_sync_from_stream(index, input) <= 0;
-		}
-
-		i_stream_unref(input);
-	}
-
-	return !failed;
-}
--- a/src/lib-index/mbox/mbox-sync.c	Tue Apr 27 00:20:15 2004 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
-#include "mail-index-util.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-static int mbox_lock_and_sync_full(struct mail_index *index,
-				   enum mail_lock_type data_lock_type)
-{
-        enum mail_lock_type lock_type;
-
-	/* syncing needs exclusive index lock and shared
-	   mbox lock, but if we'd want exclusive mbox lock
-	   we need to set it here already */
-	if (index->lock_type == MAIL_LOCK_SHARED)
-		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
-
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	if (index->mbox_lock_type == MAIL_LOCK_UNLOCK) {
-		lock_type = data_lock_type == MAIL_LOCK_EXCLUSIVE ?
-			MAIL_LOCK_EXCLUSIVE : MAIL_LOCK_SHARED;
-		if (!mbox_lock(index, lock_type))
-			return FALSE;
-	}
-
-	return mbox_sync_full(index);
-}
-
-int mbox_index_sync(struct mail_index *index, int minimal_sync __attr_unused__,
-		    enum mail_lock_type data_lock_type, int *changes)
-{
-	struct stat st;
-	int count, fd;
-
-	if (index->mailbox_readonly && data_lock_type == MAIL_LOCK_EXCLUSIVE) {
-		index_set_error(index, "sync: %s is read-only, "
-				"can't get exclusive lock",
-				index->mailbox_path);
-		return FALSE;
-	}
-
-	if (changes != NULL)
-		*changes = FALSE;
-
-	if (index->mbox_sync_counter == index->mbox_lock_counter) {
-		/* we've already synced in this locking session */
-		return TRUE;
-	}
-
-	i_assert(index->lock_type != MAIL_LOCK_SHARED);
-
-	count = 0;
-	while (stat(index->mailbox_path, &st) < 0) {
-		if (errno != ENOENT || ++count == 3)
-			return mbox_set_syscall_error(index, "stat()");
-
-		/* mbox was deleted by someone - happens with some MUAs
-		   when all mail is expunged. easiest way to deal with this
-		   is to recreate the file. */
-		fd = open(index->mailbox_path, O_RDWR | O_CREAT | O_EXCL, 0660);
-		if (fd != -1)
-			(void)close(fd);
-		else if (errno != EEXIST)
-			return mbox_set_syscall_error(index, "open()");
-	}
-
-	if (index->mbox_fd != -1 &&
-	    (index->mbox_ino != st.st_ino ||
-	     !CMP_DEV_T(index->mbox_dev, st.st_dev))) {
-		/* mbox file was overwritten, close it if it was open */
-		index->mbox_dev = st.st_dev;
-		index->mbox_ino = st.st_ino;
-		index->sync_size = (uoff_t)-1;
-		index->sync_stamp = (time_t)-1;
-
-                mbox_file_close_fd(index);
-	}
-
-	if (index->sync_stamp != st.st_mtime ||
-	    index->sync_size != (uoff_t)st.st_size) {
-		mbox_file_close_stream(index);
-
-		if (changes != NULL)
-			*changes = TRUE;
-
-		if (!mbox_lock_and_sync_full(index, data_lock_type))
-			return FALSE;
-
-		if ((index->set_flags & MAIL_INDEX_HDR_FLAG_REBUILD) != 0) {
-			/* uidvalidity probably changed, rebuild */
-			if (!index->rebuild(index))
-				return FALSE;
-		}
-
-		if (fstat(index->mbox_fd, &st) < 0)
-			return mbox_set_syscall_error(index, "fstat()");
-
-		index->sync_stamp = st.st_mtime;
-		index->sync_size = st.st_size;
-	}
-
-	/* we need some index lock to be able to lock mbox */
-	if (index->lock_type == MAIL_LOCK_UNLOCK) {
-		if (!index->set_lock(index, MAIL_LOCK_SHARED))
-			return FALSE;
-	}
-
-	if (data_lock_type == MAIL_LOCK_UNLOCK) {
-		if (!mbox_unlock(index))
-			return FALSE;
-	} else {
-		if (!mbox_lock(index, data_lock_type))
-			return FALSE;
-	}
-
-	index->mbox_sync_counter = index->mbox_lock_counter;
-	return TRUE;
-}