[dovecot-cvs] dovecot/src/lib-storage/index/maildir Makefile.am, 1.3, 1.4 maildir-copy.c, 1.36, 1.37 maildir-keywords.c, NONE, 1.1 maildir-keywords.h, NONE, 1.1 maildir-save.c, 1.51, 1.52 maildir-storage.c, 1.100, 1.101 maildir-storage.h, 1.39, 1.40 maildir-sync.c, 1.58, 1.59 maildir-uidlist.c, 1.37, 1.38 maildir-uidlist.h, 1.13, 1.14 maildir-util.c, 1.12, 1.13

cras at dovecot.org cras at dovecot.org
Thu Jun 30 23:28:23 EEST 2005


Update of /var/lib/cvs/dovecot/src/lib-storage/index/maildir
In directory talvi:/tmp/cvs-serv9342

Modified Files:
	Makefile.am maildir-copy.c maildir-save.c maildir-storage.c 
	maildir-storage.h maildir-sync.c maildir-uidlist.c 
	maildir-uidlist.h maildir-util.c 
Added Files:
	maildir-keywords.c maildir-keywords.h 
Log Message:
Keywords are stored in maildir filename and maildir-keywords file
(backwards compatible with 0.99.x's .customflags file)



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Makefile.am	20 Oct 2004 23:06:02 -0000	1.3
+++ Makefile.am	30 Jun 2005 20:28:20 -0000	1.4
@@ -11,6 +11,7 @@
 
 libstorage_maildir_a_SOURCES = \
 	maildir-copy.c \
+	maildir-keywords.c \
 	maildir-list.c \
 	maildir-mail.c \
 	maildir-save.c \
@@ -21,5 +22,6 @@
 	maildir-util.c
 
 noinst_HEADERS = \
+	maildir-keywords.h \
 	maildir-storage.h \
 	maildir-uidlist.h

Index: maildir-copy.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-copy.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- maildir-copy.c	8 Apr 2005 14:32:51 -0000	1.36
+++ maildir-copy.c	30 Jun 2005 20:28:20 -0000	1.37
@@ -64,11 +64,22 @@
 	enum mail_flags flags;
 	const char *const *keywords;
 	const char *dest_fname;
+	array_t ARRAY_DEFINE(keywords_arr, const char *);
+	unsigned int count;
 
         flags = mail_get_flags(mail);
         keywords = mail_get_keywords(mail);
 	dest_fname = maildir_generate_tmp_filename(&ioloop_timeval);
-	dest_fname = maildir_filename_set_flags(dest_fname, flags, keywords);
+
+	count = strarray_length(keywords);
+	if (count > 0) {
+		ARRAY_CREATE(&keywords_arr, pool_datastack_create(),
+			     const char *, count);
+		array_append(&keywords_arr, keywords, count);
+	}
+	dest_fname = maildir_filename_set_flags(NULL, // FIXME: !!!
+						dest_fname, flags, count != 0 ?
+						&keywords_arr : NULL);
 
 	memset(&do_ctx, 0, sizeof(do_ctx));
 	do_ctx.dest_path =

--- NEW FILE: maildir-keywords.c ---
/* Copyright (C) 2005 Timo Sirainen */

/* note that everything here depends on uidlist file being locked the whole
   time. that's why we don't have any locking of our own, or that we do things
   that would be racy otherwise. */

#include "lib.h"
#include "ioloop.h"
#include "hash.h"
#include "str.h"
#include "istream.h"
#include "file-dotlock.h"
#include "write-full.h"
#include "maildir-storage.h"
#include "maildir-uidlist.h"
#include "maildir-keywords.h"

#include <stdlib.h>
#include <sys/stat.h>
#include <utime.h>

struct maildir_keywords {
	struct maildir_mailbox *mbox;
	char *path;

	pool_t pool;
	array_t ARRAY_DEFINE(list, const char *);
	struct hash_table *hash; /* name -> idx+1 */

        struct dotlock_settings dotlock_settings;

	time_t synced_mtime;
	unsigned int synced:1;
	unsigned int changed:1;
};

struct maildir_keywords_sync_ctx {
	struct maildir_keywords *mk;
	struct mail_index *index;

	const array_t *ARRAY_DEFINE_PTR(keywords, const char *);
	array_t ARRAY_DEFINE(idx_to_chr, char);
	unsigned int chridx_to_idx[MAILDIR_MAX_KEYWORDS];
};

struct maildir_keywords *maildir_keywords_init(struct maildir_mailbox *mbox)
{
	struct maildir_keywords *mk;

	mk = i_new(struct maildir_keywords, 1);
	mk->mbox = mbox;
	mk->path = i_strconcat(mbox->control_dir,
			       "/" MAILDIR_KEYWORDS_NAME, NULL);
	mk->pool = pool_alloconly_create("maildir keywords", 256);
	ARRAY_CREATE(&mk->list, default_pool,
		     const char *, MAILDIR_MAX_KEYWORDS);
	mk->hash = hash_create(default_pool, mk->pool, 0,
			       strcase_hash, (hash_cmp_callback_t *)strcasecmp);
	return mk;
}

void maildir_keywords_deinit(struct maildir_keywords *mk)
{
	hash_destroy(mk->hash);
	array_free(&mk->list);
	i_free(mk->path);
	i_free(mk);
}

static void maildir_keywords_clear(struct maildir_keywords *mk)
{
	array_clear(&mk->list);
	hash_clear(mk->hash, FALSE);
	p_clear(mk->pool);
}

static int maildir_keywords_sync(struct maildir_keywords *mk)
{
	struct istream *input;
	struct stat st;
	char *line, *p, *new_name;
	const char **strp;
	int fd, idx;

	if (stat(mk->path, &st) < 0) {
		if (errno == ENOENT) {
			maildir_keywords_clear(mk);
			mk->synced = TRUE;
			return 0;
		}
                mail_storage_set_critical(STORAGE(mk->mbox->storage),
					  "stat(%s) failed: %m", mk->path);
		return -1;
	}

	if (st.st_mtime == mk->synced_mtime) {
		/* hasn't changed */
		mk->synced = TRUE;
		return 0;
	}
	mk->synced_mtime = st.st_mtime;

	fd = open(mk->path, O_RDONLY);
	if (fd == -1) {
		if (errno == ENOENT) {
			maildir_keywords_clear(mk);
			mk->synced = TRUE;
			return 0;
		}
                mail_storage_set_critical(STORAGE(mk->mbox->storage),
					  "open(%s) failed: %m", mk->path);
		return -1;
	}

	maildir_keywords_clear(mk);
	input = i_stream_create_file(fd, default_pool, 1024, FALSE);
	while ((line = i_stream_read_next_line(input)) != NULL) {
		p = strchr(line, ' ');
		if (p == NULL) {
			/* note that when converting .customflags file this
			   case happens in the first line. */
			continue;
		}
		*p++ = '\0';

		idx = atoi(line);
		if (idx < 0 || idx >= MAILDIR_MAX_KEYWORDS) {
			/* shouldn't happen */
			continue;
		}

		/* save it */
		new_name = p_strdup(mk->pool, p);
		hash_insert(mk->hash, new_name, POINTER_CAST(idx + 1));

		strp = array_idx_modifyable(&mk->list, idx);
		*strp = new_name;
	}
	i_stream_unref(input);

	if (close(fd) < 0) {
                mail_storage_set_critical(STORAGE(mk->mbox->storage),
					  "close(%s) failed: %m", mk->path);
		return -1;
	}

	mk->synced = TRUE;
	return 0;
}

static int
maildir_keywords_lookup(struct maildir_keywords *mk, const char *name)
{
	void *p;

	i_assert(maildir_uidlist_is_locked(mk->mbox->uidlist));

	p = hash_lookup(mk->hash, name);
	if (p == NULL) {
		if (mk->synced)
			return -1;

		if (maildir_keywords_sync(mk) < 0)
			return -1;

		p = hash_lookup(mk->hash, name);
		if (p == NULL)
			return -1;
	}

	return POINTER_CAST_TO(p, int)-1;
}

static void
maildir_keywords_create(struct maildir_keywords *mk, const char *name,
			unsigned int chridx)
{
	const char **strp;
	char *new_name;

	i_assert(chridx < MAILDIR_MAX_KEYWORDS);

	new_name = p_strdup(mk->pool, name);
	hash_insert(mk->hash, new_name, POINTER_CAST(chridx + 1));

	strp = array_idx_modifyable(&mk->list, chridx);
	*strp = new_name;

	mk->changed = TRUE;
}

static int
maildir_keywords_lookup_or_create(struct maildir_keywords *mk, const char *name)
{
	const char *const *keywords;
	unsigned int i, count;
	int idx;

	idx = maildir_keywords_lookup(mk, name);
	if (idx >= 0)
		return idx;
	i_assert(mk->synced);

	/* see if we are full */
	keywords = array_get(&mk->list, &count);
	for (i = 0; i < count; i++) {
		if (keywords[i] == NULL)
			break;
	}

	if (i == count && count >= MAILDIR_MAX_KEYWORDS)
		return -1;

        maildir_keywords_create(mk, name, i);
	return i;
}

static const char *
maildir_keywords_idx(struct maildir_keywords *mk, unsigned int idx)
{
	const char *const *keywords;
	unsigned int count;

	i_assert(maildir_uidlist_is_locked(mk->mbox->uidlist));

	keywords = array_get(&mk->list, &count);
	if (idx >= count) {
		if (mk->synced)
			return NULL;

		if (maildir_keywords_sync(mk) < 0)
			return NULL;

		keywords = array_get(&mk->list, &count);
	}
	return idx >= count ? NULL : keywords[idx];
}

static int maildir_keywords_commit(struct maildir_keywords *mk)
{
	struct dotlock *dotlock;
	const char *lock_path, *const *keywords;
	unsigned int i, count;
	struct utimbuf ut;
	string_t *str;
	int fd;

	mk->synced = FALSE;

	if (!mk->changed)
		return 0;

	/* we could just create the temp file directly, but doing it this
	   ways avoids potential problems with overwriting contents in
	   malicious symlinks */
	t_push();
	lock_path = t_strconcat(mk->path, ".lock", NULL);
	(void)unlink(lock_path);
	fd = file_dotlock_open(&mk->dotlock_settings, mk->path,
			       DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
	if (fd == -1) {
		mail_storage_set_critical(STORAGE(mk->mbox->storage),
			"file_dotlock_open(%s) failed: %m", mk->path);
		t_pop();
		return -1;
	}

	str = t_str_new(256);
	keywords = array_get(&mk->list, &count);
	for (i = 0; i < count; i++) {
		if (keywords[i] != NULL)
			str_printfa(str, "%u %s\n", i, keywords[i]);
	}
	if (write_full(fd, str_data(str), str_len(str)) < 0) {
		mail_storage_set_critical(STORAGE(mk->mbox->storage),
			"write_full(%s) failed: %m", mk->path);
		(void)file_dotlock_delete(&dotlock);
		t_pop();
		return -1;
	}

	/* mtime must grow every time */
        mk->synced_mtime = ioloop_time <= mk->synced_mtime ?
		mk->synced_mtime + 1 : ioloop_time;
	ut.actime = ioloop_time;
	ut.modtime = mk->synced_mtime;
	if (utime(lock_path, &ut) < 0) {
		mail_storage_set_critical(STORAGE(mk->mbox->storage),
			"utime(%s) failed: %m", lock_path);
		return -1;
	}

	if (file_dotlock_replace(&dotlock, 0) < 0) {
		mail_storage_set_critical(STORAGE(mk->mbox->storage),
			"file_dotlock_replace(%s) failed: %m", mk->path);
		t_pop();
		return -1;
	}

	mk->changed = FALSE;
	t_pop();
	return 0;
}

struct maildir_keywords_sync_ctx *
maildir_keywords_sync_init(struct maildir_keywords *mk,
			   struct mail_index *index)
{
	struct maildir_keywords_sync_ctx *ctx;

	ctx = i_new(struct maildir_keywords_sync_ctx, 1);
	ctx->mk = mk;
	ctx->index = index;
	ctx->keywords = mail_index_get_keywords(index);
	ARRAY_CREATE(&ctx->idx_to_chr, default_pool,
		     char, MAILDIR_MAX_KEYWORDS);
	return ctx;
}

void maildir_keywords_sync_deinit(struct maildir_keywords_sync_ctx *ctx)
{
	maildir_keywords_commit(ctx->mk);
	array_free(&ctx->idx_to_chr);
	i_free(ctx);
}

unsigned int maildir_keywords_char_idx(struct maildir_keywords_sync_ctx *ctx,
				       char keyword)
{
	const char *name;
	unsigned int chridx, idx;

	i_assert(keyword >= MAILDIR_KEYWORD_FIRST &&
		 keyword <= MAILDIR_KEYWORD_LAST);
	chridx = keyword - MAILDIR_KEYWORD_FIRST;

	if (ctx->chridx_to_idx[chridx] != 0)
		return ctx->chridx_to_idx[chridx];

	/* lookup / create */
	name = maildir_keywords_idx(ctx->mk, chridx);
	if (name == NULL) {
		/* name is lost. just generate one ourself. */
		name = t_strdup_printf("unknown-%u", chridx);
		while (maildir_keywords_lookup(ctx->mk, name) >= 0) {
			/* don't create a duplicate name.
			   keep changing the name until it doesn't exist */
			name = t_strconcat(name, "?", NULL);
		}
                maildir_keywords_create(ctx->mk, name, chridx);
	}

	if (!mail_index_keyword_lookup(ctx->index, name, TRUE, &idx))
		i_unreached();

        ctx->chridx_to_idx[chridx] = idx;
	return idx;
}

char maildir_keywords_idx_char(struct maildir_keywords_sync_ctx *ctx,
			       unsigned int idx)
{
	const char *const *name_p;
	char *chr_p;
	int chridx;

	chr_p = array_idx_modifyable(&ctx->idx_to_chr, idx);
	if (*chr_p != '\0')
		return *chr_p;

	name_p = array_idx(ctx->keywords, idx);
	chridx = maildir_keywords_lookup_or_create(ctx->mk, *name_p);
	if (chridx < 0)
		return '\0';

	*chr_p = chridx + MAILDIR_KEYWORD_FIRST;
	return *chr_p;
}

--- NEW FILE: maildir-keywords.h ---
#ifndef __MAILDIR_KEYWORDS_H
#define __MAILDIR_KEYWORDS_H

#define MAILDIR_KEYWORDS_NAME "dovecot-keywords"

struct maildir_keywords;
struct maildir_keywords_sync_ctx;

struct maildir_keywords *maildir_keywords_init(struct maildir_mailbox *mbox);
void maildir_keywords_deinit(struct maildir_keywords *mk);

struct maildir_keywords_sync_ctx *
maildir_keywords_sync_init(struct maildir_keywords *mk,
			   struct mail_index *index);
void maildir_keywords_sync_deinit(struct maildir_keywords_sync_ctx *ctx);

/* Returns keyword index. */
unsigned int maildir_keywords_char_idx(struct maildir_keywords_sync_ctx *ctx,
				       char keyword);
/* Returns keyword character for given index, or \0 if keyword couldn't be
   added. */
char maildir_keywords_idx_char(struct maildir_keywords_sync_ctx *ctx,
			       unsigned int idx);

#endif

Index: maildir-save.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-save.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- maildir-save.c	8 Apr 2005 14:32:51 -0000	1.51
+++ maildir-save.c	30 Jun 2005 20:28:20 -0000	1.52
@@ -17,7 +17,11 @@
 
 struct maildir_filename {
 	struct maildir_filename *next;
-	const char *basename, *dest;
+	const char *basename;
+
+	enum mail_flags flags;
+	unsigned int keywords_count;
+	/* unsigned int keywords[]; */
 };
 
 struct maildir_save_context {
@@ -26,11 +30,14 @@
 
 	struct maildir_mailbox *mbox;
 	struct mail_index_transaction *trans;
-	struct maildir_uidlist_sync_ctx *sync_ctx;
+	struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
 
 	const char *tmpdir, *newdir, *curdir;
 	struct maildir_filename *files;
 
+	buffer_t *keywords_buffer;
+	array_t ARRAY_DEFINE(keywords_array, unsigned int);
+
 	struct istream *input;
 	struct ostream *output;
 	int fd;
@@ -95,6 +102,10 @@
 	ctx->tmpdir = p_strconcat(pool, mbox->path, "/tmp", NULL);
 	ctx->newdir = p_strconcat(pool, mbox->path, "/new", NULL);
 	ctx->curdir = p_strconcat(pool, mbox->path, "/cur", NULL);
+
+	ctx->keywords_buffer = buffer_create_const_data(pool, NULL, 0);
+	array_create_from_buffer(&ctx->keywords_array, ctx->keywords_buffer,
+				 sizeof(unsigned int));
 	return ctx;
 }
 
@@ -111,7 +122,7 @@
 	struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
 	struct maildir_filename *mf;
 	struct ostream *output;
-	const char *fname, *dest_fname, *path;
+	const char *fname, *path;
 
 	i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
 
@@ -150,17 +161,25 @@
 
 	/* now, we want to be able to rollback the whole append session,
 	   so we'll just store the name of this temp file and move it later
-	   into new/ or cur/. if dest_fname is NULL, it's moved to new/,
-	   otherwise to cur/. */
-	dest_fname = flags == MAIL_RECENT ? NULL :
-		maildir_filename_set_flags(fname, flags, NULL); // FIXME
-
-	mf = p_new(ctx->pool, struct maildir_filename, 1);
+	   into new/ or cur/. */
+	/* @UNSAFE */
+	mf = p_malloc(ctx->pool, sizeof(*mf) +
+		      sizeof(unsigned int) * (keywords == NULL ? 0 :
+					      keywords->count));
 	mf->next = ctx->files;
 	mf->basename = p_strdup(ctx->pool, fname);
-	mf->dest = p_strdup(ctx->pool, dest_fname);
+	mf->flags = flags;
 	ctx->files = mf;
 
+	if (keywords != NULL) {
+		i_assert(sizeof(keywords->idx[0]) == sizeof(unsigned int));
+
+		/* @UNSAFE */
+		mf->keywords_count = keywords->count;
+		memcpy(mf + 1, keywords->idx,
+		       sizeof(unsigned int) * keywords->count);
+	}
+
 	/* insert into index */
 	mail_index_append(ctx->trans, 0, &ctx->seq);
 	mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, flags);
@@ -273,26 +292,41 @@
 	(void)maildir_save_finish(_ctx, NULL);
 }
 
-static void maildir_save_commit_abort(struct maildir_save_context *ctx,
-				      struct maildir_filename *pos)
+static const char *
+maildir_get_updated_filename(struct maildir_save_context *ctx,
+			     struct maildir_index_sync_context *sync_ctx,
+			     struct maildir_filename *mf)
 {
-	struct maildir_filename *mf;
-	string_t *str;
+	if (mf->flags == MAIL_RECENT && mf->keywords_count == 0)
+		return NULL;
 
-	t_push();
-	str = t_str_new(1024);
+	buffer_update_const_data(ctx->keywords_buffer, mf + 1,
+				 mf->keywords_count * sizeof(unsigned int));
+	return maildir_filename_set_flags(sync_ctx, mf->basename,
+					  mf->flags, &ctx->keywords_array);
+}
+
+static void
+maildir_save_commit_abort(struct maildir_save_context *ctx,
+			  struct maildir_index_sync_context *sync_ctx,
+			  struct maildir_filename *pos)
+{
+	struct maildir_filename *mf;
+	const char *path, *dest;
 
 	/* try to unlink the mails already moved */
 	for (mf = ctx->files; mf != pos; mf = mf->next) {
-		str_truncate(str, 0);
-		if (mf->dest == NULL)
-			str_printfa(str, "%s/%s", ctx->newdir, mf->basename);
-		else
-			str_printfa(str, "%s/%s", ctx->curdir, mf->dest);
-		(void)unlink(str_c(str));
+		t_push();
+		dest = maildir_get_updated_filename(ctx, sync_ctx, mf);
+		if (dest != NULL)
+			path = t_strdup_printf("%s/%s", ctx->curdir, dest);
+		else {
+			path = t_strdup_printf("%s/%s",
+					       ctx->newdir, mf->basename);
+		}
+		(void)unlink(path);
 	}
 	ctx->files = pos;
-	t_pop();
 
 	maildir_transaction_save_rollback(ctx);
 }
@@ -303,14 +337,14 @@
 	struct maildir_filename *mf;
 	uint32_t first_uid, last_uid;
 	enum maildir_uidlist_rec_flag flags;
-	const char *fname;
+	const char *dest, *fname;
 	int ret;
 
 	i_assert(ctx->output == NULL);
 
 	sync_ctx = maildir_sync_index_begin(ctx->mbox);
 	if (sync_ctx == NULL) {
-		maildir_save_commit_abort(ctx, ctx->files);
+		maildir_save_commit_abort(ctx, sync_ctx, ctx->files);
 		return -1;
 	}
 
@@ -318,12 +352,12 @@
 	if (ret <= 0) {
 		/* error or timeout - our transaction is broken */
 		maildir_sync_index_abort(sync_ctx);
-		maildir_save_commit_abort(ctx, ctx->files);
+		maildir_save_commit_abort(ctx, sync_ctx, ctx->files);
 		return -1;
 	}
 
 	if (maildir_sync_index_finish(sync_ctx, TRUE) < 0) {
-		maildir_save_commit_abort(ctx, ctx->files);
+		maildir_save_commit_abort(ctx, sync_ctx, ctx->files);
 		return -1;
 	}
 
@@ -334,25 +368,32 @@
 		MAILDIR_UIDLIST_REC_FLAG_RECENT;
 
 	/* move them into new/ */
-	ctx->sync_ctx = maildir_uidlist_sync_init(ctx->mbox->uidlist, TRUE);
+	ctx->uidlist_sync_ctx =
+		maildir_uidlist_sync_init(ctx->mbox->uidlist, TRUE);
+
 	for (mf = ctx->files; mf != NULL; mf = mf->next) {
-		fname = mf->dest != NULL ? mf->dest : mf->basename;
-		if (maildir_file_move(ctx, mf->basename, mf->dest) < 0 ||
-		    maildir_uidlist_sync_next(ctx->sync_ctx,
+		t_push();
+		dest = maildir_get_updated_filename(ctx, sync_ctx, mf);
+		fname = dest != NULL ? dest : mf->basename;
+
+		if (maildir_file_move(ctx, mf->basename, dest) < 0 ||
+		    maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
 					      fname, flags) < 0) {
-			(void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
-			maildir_save_commit_abort(ctx, mf);
+			(void)maildir_uidlist_sync_deinit(
+							ctx->uidlist_sync_ctx);
+			maildir_save_commit_abort(ctx, sync_ctx, mf);
+			t_pop();
 			return -1;
 		}
+		t_pop();
 	}
-
 	return 0;
 }
 
 void maildir_transaction_save_commit_post(struct maildir_save_context *ctx)
 {
 	/* can't do anything anymore if we fail */
-	(void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
+	(void)maildir_uidlist_sync_deinit(ctx->uidlist_sync_ctx);
 
 	pool_unref(ctx->pool);
 }

Index: maildir-storage.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.c,v
retrieving revision 1.100
retrieving revision 1.101
diff -u -d -r1.100 -r1.101
--- maildir-storage.c	9 Jun 2005 14:31:43 -0000	1.100
+++ maildir-storage.c	30 Jun 2005 20:28:20 -0000	1.101
@@ -8,6 +8,7 @@
 #include "subscription-file/subscription-file.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
+#include "maildir-keywords.h"
 #include "index-mail.h"
 
 #include <stdio.h>
@@ -460,6 +461,7 @@
 	mbox->control_dir = p_strdup(pool, control_dir);
 
 	mbox->uidlist = maildir_uidlist_init(mbox);
+	mbox->keywords = maildir_keywords_init(mbox);
 
 	if (!shared)
 		mbox->mail_create_mode = 0600;
@@ -847,6 +849,7 @@
 		ret = -1;
 	}*/
 
+	maildir_keywords_deinit(mbox->keywords);
 	maildir_uidlist_deinit(mbox->uidlist);
         index_storage_mailbox_free(box);
 	return ret;

Index: maildir-storage.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.h,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- maildir-storage.h	9 Jun 2005 14:43:07 -0000	1.39
+++ maildir-storage.h	30 Jun 2005 20:28:20 -0000	1.40
@@ -21,6 +21,10 @@
 /* ":2," is the standard flags separator */
 #define MAILDIR_FLAGS_FULL_SEP MAILDIR_INFO_SEP_S "2" MAILDIR_FLAGS_SEP_S
 
+#define MAILDIR_KEYWORD_FIRST 'a'
+#define MAILDIR_KEYWORD_LAST 'z'
+#define MAILDIR_MAX_KEYWORDS (MAILDIR_KEYWORD_LAST - MAILDIR_KEYWORD_FIRST + 1)
+
 /* Maildir++ extension: include file size in the filename to avoid stat() */
 #define MAILDIR_EXTRA_FILE_SIZE "S"
 /* Something (can't remember what anymore) could use 'W' in filename to avoid
@@ -52,6 +56,7 @@
 
 	/* maildir sync: */
 	struct maildir_uidlist *uidlist;
+	struct maildir_keywords *keywords;
 	time_t last_new_mtime, last_cur_mtime, last_new_sync_time;
 	time_t dirty_cur_time;
 
@@ -127,11 +132,13 @@
 
 int maildir_sync_last_commit(struct maildir_mailbox *mbox);
 
-int maildir_filename_get_flags(const char *fname, pool_t pool,
+int maildir_filename_get_flags(struct maildir_index_sync_context *ctx,
+			       const char *fname,
 			       enum mail_flags *flags_r,
-			       const char *const **keywords_r);
-const char *maildir_filename_set_flags(const char *fname, enum mail_flags flags,
-				       const char *const *keywords);
+			       array_t *keywords);
+const char *maildir_filename_set_flags(struct maildir_index_sync_context *ctx,
+				       const char *fname, enum mail_flags flags,
+				       array_t *keywords);
 
 unsigned int maildir_hash(const void *p);
 int maildir_cmp(const void *p1, const void *p2);

Index: maildir-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-sync.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -d -r1.58 -r1.59
--- maildir-sync.c	28 Jun 2005 22:32:38 -0000	1.58
+++ maildir-sync.c	30 Jun 2005 20:28:20 -0000	1.59
@@ -177,6 +177,7 @@
 #include "str.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
+#include "maildir-keywords.h"
 
 #include <stdio.h>
 #include <stddef.h>
@@ -209,6 +210,7 @@
         struct maildir_mailbox *mbox;
 	struct mail_index_view *view;
 	struct mail_index_sync_ctx *sync_ctx;
+        struct maildir_keywords_sync_ctx *keywords_sync_ctx;
 	struct mail_index_transaction *trans;
 
 	array_t ARRAY_DEFINE(sync_recs, struct mail_index_sync_rec);
@@ -216,6 +218,162 @@
 	int dirty_state;
 };
 
+int maildir_filename_get_flags(struct maildir_index_sync_context *ctx,
+			       const char *fname,
+			       enum mail_flags *flags_r,
+                               array_t *keywords_r)
+{
+	ARRAY_SET_TYPE(keywords_r, unsigned int);
+	const char *info;
+
+	array_clear(keywords_r);
+	*flags_r = 0;
+
+	info = strchr(fname, MAILDIR_INFO_SEP);
+	if (info == NULL || info[1] != '2' || info[2] != MAILDIR_FLAGS_SEP)
+		return 0;
+
+	for (info += 3; *info != '\0' && *info != MAILDIR_FLAGS_SEP; info++) {
+		switch (*info) {
+		case 'R': /* replied */
+			*flags_r |= MAIL_ANSWERED;
+			break;
+		case 'S': /* seen */
+			*flags_r |= MAIL_SEEN;
+			break;
+		case 'T': /* trashed */
+			*flags_r |= MAIL_DELETED;
+			break;
+		case 'D': /* draft */
+			*flags_r |= MAIL_DRAFT;
+			break;
+		case 'F': /* flagged */
+			*flags_r |= MAIL_FLAGGED;
+			break;
+		default:
+			if (*info >= MAILDIR_KEYWORD_FIRST &&
+			    *info <= MAILDIR_KEYWORD_LAST) {
+				int idx;
+
+				idx = maildir_keywords_char_idx(
+						ctx->keywords_sync_ctx, *info);
+				if (idx < 0) {
+					/* unknown keyword. */
+					break;
+				}
+
+				array_append(keywords_r, &idx, 1);
+				break;
+			}
+
+			/* unknown flag - ignore */
+			break;
+		}
+	}
+
+	return 1;
+}
+
+static void
+maildir_filename_append_keywords(struct maildir_keywords_sync_ctx *ctx,
+				 array_t *keywords, string_t *str)
+{
+	ARRAY_SET_TYPE(keywords, unsigned int);
+	const unsigned int *indexes;
+	unsigned int i, count;
+	char chr;
+
+	indexes = array_get(keywords, &count);
+	for (i = 0; i < count; i++) {
+		chr = maildir_keywords_idx_char(ctx, indexes[i]);
+		if (chr != '\0')
+			str_append_c(str, chr);
+	}
+}
+
+const char *maildir_filename_set_flags(struct maildir_index_sync_context *ctx,
+				       const char *fname, enum mail_flags flags,
+				       array_t *keywords)
+{
+	string_t *flags_str;
+	enum mail_flags flags_left;
+	const char *info, *oldflags;
+	int nextflag;
+
+	/* remove the old :info from file name, and get the old flags */
+	info = strrchr(fname, MAILDIR_INFO_SEP);
+	if (info != NULL && strrchr(fname, '/') > info)
+		info = NULL;
+
+	oldflags = "";
+	if (info != NULL) {
+		fname = t_strdup_until(fname, info);
+		if (info[1] == '2' && info[2] == MAILDIR_FLAGS_SEP)
+			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, MAILDIR_FLAGS_FULL_SEP);
+	flags_left = flags;
+	for (;;) {
+		/* skip all known flags */
+		while (*oldflags == 'D' || *oldflags == 'F' ||
+		       *oldflags == 'R' || *oldflags == 'S' ||
+		       *oldflags == 'T' ||
+		       (*oldflags >= MAILDIR_KEYWORD_FIRST &&
+			*oldflags <= MAILDIR_KEYWORD_LAST))
+			oldflags++;
+
+		nextflag = *oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP ?
+			256 : (unsigned char) *oldflags;
+
+		if ((flags_left & MAIL_DRAFT) && nextflag > 'D') {
+			str_append_c(flags_str, 'D');
+			flags_left &= ~MAIL_DRAFT;
+		}
+		if ((flags_left & MAIL_FLAGGED) && nextflag > 'F') {
+			str_append_c(flags_str, 'F');
+			flags_left &= ~MAIL_FLAGGED;
+		}
+		if ((flags_left & MAIL_ANSWERED) && nextflag > 'R') {
+			str_append_c(flags_str, 'R');
+			flags_left &= ~MAIL_ANSWERED;
+		}
+		if ((flags_left & MAIL_SEEN) && nextflag > 'S') {
+			str_append_c(flags_str, 'S');
+			flags_left &= ~MAIL_SEEN;
+		}
+		if ((flags_left & MAIL_DELETED) && nextflag > 'T') {
+			str_append_c(flags_str, 'T');
+			flags_left &= ~MAIL_DELETED;
+		}
+
+		if (keywords != NULL && array_is_created(keywords) &&
+		    nextflag > MAILDIR_KEYWORD_FIRST) {
+			maildir_filename_append_keywords(ctx->keywords_sync_ctx,
+							 keywords, flags_str);
+			keywords = NULL;
+		}
+
+		if (*oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP)
+			break;
+
+		str_append_c(flags_str, *oldflags);
+		oldflags++;
+	}
+
+	if (*oldflags == MAILDIR_FLAGS_SEP) {
+		/* 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);
+}
+
 static int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
 			   void *context __attr_unused__)
 {
@@ -238,14 +396,14 @@
 	const struct mail_index_sync_rec *recs;
 	const char *newpath;
 	enum mail_flags flags;
-	const char *const *keywords;
+	array_t ARRAY_DEFINE(keywords, unsigned int);
 	unsigned int i, count;
 	uint8_t flags8;
 
 	ctx->dirty_state = 0;
 
-	(void)maildir_filename_get_flags(path, pool_datastack_create(),
-					 &flags, &keywords);
+	ARRAY_CREATE(&keywords, pool_datastack_create(), unsigned int, 16);
+	(void)maildir_filename_get_flags(ctx, path, &flags, &keywords);
 	flags8 = flags;
 
 	recs = array_get_modifyable(&ctx->sync_recs, &count);
@@ -260,7 +418,7 @@
 		case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
 		case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
 		case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
-			/*FIXME:mail_index_sync_keywords_apply(&recs[i], &keywords);*/
+			mail_index_sync_keywords_apply(&recs[i], &keywords);
 			break;
 		case MAIL_INDEX_SYNC_TYPE_APPEND:
 		case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
@@ -269,7 +427,7 @@
 		}
 	}
 
-	newpath = maildir_filename_set_flags(path, flags8, keywords);
+	newpath = maildir_filename_set_flags(ctx, path, flags8, &keywords);
 	if (rename(path, newpath) == 0) {
 		if ((flags8 & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
 			ctx->dirty_state = -1;
@@ -381,6 +539,11 @@
 					&sync_copy.uid2) < 0)
 		return -1;
 
+	if (sync_copy.uid1 == 0) {
+		/* UIDs were expunged */
+		return 0;
+	}
+
 	while (array_count(&ctx->sync_recs) > 0) {
 		const struct mail_index_sync_rec *rec =
 			array_idx(&ctx->sync_recs, 0);
@@ -420,44 +583,6 @@
 	return ret;
 }
 
-int maildir_sync_last_commit(struct maildir_mailbox *mbox)
-{
-	struct maildir_index_sync_context ctx;
-	uint32_t seq;
-	uoff_t offset;
-	int ret;
-
-	if (mbox->ibox.commit_log_file_seq == 0)
-		return 0;
-
-	memset(&ctx, 0, sizeof(ctx));
-	ctx.mbox = mbox;
-
-        mbox->syncing_commit = TRUE;
-	ret = mail_index_sync_begin(mbox->ibox.index, &ctx.sync_ctx, &ctx.view,
-				    mbox->ibox.commit_log_file_seq,
-				    mbox->ibox.commit_log_file_offset,
-				    FALSE, FALSE);
-	if (ret > 0) {
-		ctx.trans = mail_index_transaction_begin(ctx.view, FALSE, TRUE);
-		if (maildir_sync_index_records(&ctx) < 0)
-			ret = -1;
-		if (mail_index_transaction_commit(ctx.trans, &seq, &offset) < 0)
-			ret = -1;
-		if (mail_index_sync_commit(ctx.sync_ctx) < 0)
-			ret = -1;
-	}
-        mbox->syncing_commit = FALSE;
-
-	if (ret == 0) {
-		mbox->ibox.commit_log_file_seq = 0;
-		mbox->ibox.commit_log_file_offset = 0;
-	} else {
-		mail_storage_set_index_error(&mbox->ibox);
-	}
-	return ret;
-}
-
 static struct maildir_sync_context *
 maildir_sync_context_new(struct maildir_mailbox *mbox)
 {
@@ -678,14 +803,19 @@
 				  &sync_ctx->view, (uint32_t)-1, (uoff_t)-1,
 				  FALSE, FALSE) <= 0) {
 		mail_storage_set_index_error(&mbox->ibox);
+		i_free(sync_ctx);
 		return NULL;
 	}
+
+	sync_ctx->keywords_sync_ctx =
+		maildir_keywords_sync_init(mbox->keywords, mbox->ibox.index);
 	return sync_ctx;
 }
 
 void maildir_sync_index_abort(struct maildir_index_sync_context *sync_ctx)
 {
 	mail_index_sync_rollback(sync_ctx->sync_ctx);
+	maildir_keywords_sync_deinit(sync_ctx->keywords_sync_ctx);
 	i_free(sync_ctx);
 }
 
@@ -698,12 +828,12 @@
 	struct mail_index_transaction *trans;
 	const struct mail_index_header *hdr;
 	const struct mail_index_record *rec;
-	pool_t keyword_pool;
 	uint32_t seq, uid;
         enum maildir_uidlist_rec_flag uflags;
 	const char *filename;
 	enum mail_flags flags;
-	const char *const *keywords;
+	array_t ARRAY_DEFINE(keywords, unsigned int);
+	array_t ARRAY_DEFINE(idx_keywords, unsigned int);
 	uint32_t uid_validity, next_uid;
 	int ret = 0, full_rescan = FALSE;
 
@@ -724,13 +854,14 @@
 		return -1;
 	}
 
-	keyword_pool = pool_alloconly_create("maildir keywords", 128);
-
 	seq = 0;
+	ARRAY_CREATE(&keywords, pool_datastack_create(),
+		     unsigned int, MAILDIR_MAX_KEYWORDS);
+	ARRAY_CREATE(&idx_keywords, pool_datastack_create(),
+		     unsigned int, MAILDIR_MAX_KEYWORDS);
 	iter = maildir_uidlist_iter_init(mbox->uidlist);
 	while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
-		p_clear(keyword_pool);
-		maildir_filename_get_flags(filename, keyword_pool,
+		maildir_filename_get_flags(sync_ctx, filename,
 					   &flags, &keywords);
 
 		if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 &&
@@ -785,7 +916,16 @@
 			mail_index_append(trans, uid, &seq);
 			mail_index_update_flags(trans, seq, MODIFY_REPLACE,
 						flags);
-			// FIXME: set keywords
+
+			if (array_count(&keywords) > 0) {
+				struct mail_keywords *kw;
+
+				kw = mail_index_keywords_create_from_indexes(
+					trans, &keywords);
+				mail_index_update_keywords(trans, seq,
+							   MODIFY_REPLACE, kw);
+				mail_index_keywords_free(kw);
+			}
 			continue;
 		}
 
@@ -873,10 +1013,25 @@
 			mail_index_update_flags(trans, seq, MODIFY_REMOVE,
 						MAIL_RECENT);
 		}
-		// FIXME: update keywords
+
+		/* update keywords if they have changed */
+		array_clear(&idx_keywords);
+		if (mail_index_lookup_keywords(view, seq, &idx_keywords) < 0) {
+			ret = -1;
+			break;
+		}
+		if (!array_cmp(&keywords, &idx_keywords)) {
+			struct mail_keywords *kw;
+
+			kw = mail_index_keywords_create_from_indexes(
+				trans, &keywords);
+			mail_index_update_keywords(trans, seq,
+						   MODIFY_REPLACE, kw);
+			mail_index_keywords_free(kw);
+		}
 	}
 	maildir_uidlist_iter_deinit(iter);
-	pool_unref(keyword_pool);
+	array_free(&keywords);
 
 	if (!partial) {
 		/* expunge the rest */
@@ -943,6 +1098,7 @@
 		if (mail_index_sync_commit(sync_ctx->sync_ctx) < 0)
 			ret = -1;
 	}
+	maildir_keywords_sync_deinit(sync_ctx->keywords_sync_ctx);
 
 	if (ret == 0) {
 		mbox->ibox.commit_log_file_seq = 0;
@@ -955,12 +1111,15 @@
 	return ret < 0 ? -1 : (full_rescan ? 0 : 1);
 }
 
-static int maildir_sync_context(struct maildir_sync_context *ctx, int forced)
+static int maildir_sync_context(struct maildir_sync_context *ctx, int forced,
+				int sync_last_commit)
 {
 	int ret, new_changed, cur_changed;
 	int full_rescan = FALSE;
 
-	if (!forced) {
+	if (sync_last_commit) {
+		new_changed = cur_changed = FALSE;
+	} else if (!forced) {
 		if (maildir_sync_quick_check(ctx, &new_changed, &cur_changed) < 0)
 			return -1;
 
@@ -1032,20 +1191,26 @@
 	ctx->uidlist_sync_ctx =
 		maildir_uidlist_sync_init(ctx->mbox->uidlist, ctx->partial);
 
-	while ((ret = maildir_scan_dir(ctx, TRUE)) > 0) {
-		/* rename()d at least some files, which might have caused some
-		   other files to be missed. check again (see
-		   MAILDIR_RENAME_RESCAN_COUNT). */
-	}
-	if (ret < 0)
-		return -1;
-	if (cur_changed) {
-		if (maildir_scan_dir(ctx, FALSE) < 0)
+	if (new_changed || cur_changed) {
+		/* if we're going to check cur/ dir our current logic requires
+		   that new/ dir is checked as well. it's a good idea anyway. */
+		while ((ret = maildir_scan_dir(ctx, TRUE)) > 0) {
+			/* rename()d at least some files, which might have
+			   caused some other files to be missed. check again
+			   (see MAILDIR_RENAME_RESCAN_COUNT). */
+		}
+		if (ret < 0)
 			return -1;
+
+		if (cur_changed) {
+			if (maildir_scan_dir(ctx, FALSE) < 0)
+				return -1;
+		}
+
+		/* finish uidlist syncing, but keep it still locked */
+		maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx);
 	}
 
-	/* finish uidlist syncing, but keep it still locked */
-	maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx);
 	if (!ctx->mbox->syncing_commit) {
 		ret = maildir_sync_index_finish(ctx->index_sync_ctx,
 						ctx->partial);
@@ -1055,11 +1220,13 @@
 		}
 		if (ret == 0)
 			full_rescan = TRUE;
+
+		i_assert(maildir_uidlist_is_locked(ctx->mbox->uidlist));
 		ctx->index_sync_ctx = NULL;
 	}
 
 	ret = maildir_uidlist_sync_deinit(ctx->uidlist_sync_ctx);
-        ctx->uidlist_sync_ctx = NULL;
+	ctx->uidlist_sync_ctx = NULL;
 
 	return ret < 0 ? -1 : (full_rescan ? 0 : 1);
 }
@@ -1070,7 +1237,21 @@
 	int ret;
 
 	ctx = maildir_sync_context_new(mbox);
-	ret = maildir_sync_context(ctx, TRUE);
+	ret = maildir_sync_context(ctx, TRUE, FALSE);
+	maildir_sync_deinit(ctx);
+	return ret < 0 ? -1 : 0;
+}
+
+int maildir_sync_last_commit(struct maildir_mailbox *mbox)
+{
+        struct maildir_sync_context *ctx;
+	int ret;
+
+	if (mbox->ibox.commit_log_file_seq == 0)
+		return 0;
+
+	ctx = maildir_sync_context_new(mbox);
+	ret = maildir_sync_context(ctx, FALSE, TRUE);
 	maildir_sync_deinit(ctx);
 	return ret < 0 ? -1 : 0;
 }
@@ -1088,9 +1269,11 @@
 		mbox->ibox.sync_last_check = ioloop_time;
 
 		ctx = maildir_sync_context_new(mbox);
-		ret = maildir_sync_context(ctx, FALSE);
+		ret = maildir_sync_context(ctx, FALSE, FALSE);
 		maildir_sync_deinit(ctx);
 
+		i_assert(!maildir_uidlist_is_locked(mbox->uidlist));
+
 		if (ret == 0) {
 			/* lost some files from new/, see if thery're in cur/ */
 			ret = maildir_storage_sync_force(mbox);

Index: maildir-uidlist.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-uidlist.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- maildir-uidlist.c	8 Apr 2005 14:32:51 -0000	1.37
+++ maildir-uidlist.c	30 Jun 2005 20:28:20 -0000	1.38
@@ -20,7 +20,7 @@
 #define UIDLIST_LOCK_STALE_TIMEOUT (60*5)
 
 #define UIDLIST_IS_LOCKED(uidlist) \
-	((uidlist)->lock_fd != -1)
+	((uidlist)->lock_count > 0)
 
 struct maildir_uidlist_rec {
 	uint32_t uid;
@@ -31,7 +31,9 @@
 struct maildir_uidlist {
 	struct maildir_mailbox *mbox;
 	char *fname;
+
 	int lock_fd;
+	unsigned int lock_count;
 
 	time_t last_mtime;
 
@@ -75,8 +77,10 @@
 	mode_t old_mask;
 	int fd;
 
-	if (UIDLIST_IS_LOCKED(uidlist))
+	if (uidlist->lock_count > 0) {
+		uidlist->lock_count++;
 		return 1;
+	}
 
 	path = t_strconcat(uidlist->mbox->control_dir,
 			   "/" MAILDIR_UIDLIST_NAME, NULL);
@@ -98,6 +102,7 @@
 	if (maildir_uidlist_update(uidlist) < 0)
 		return -1;
 
+	uidlist->lock_count++;
 	return 1;
 }
 
@@ -111,9 +116,16 @@
 	return maildir_uidlist_lock_timeout(uidlist, TRUE);
 }
 
+int maildir_uidlist_is_locked(struct maildir_uidlist *uidlist)
+{
+	return UIDLIST_IS_LOCKED(uidlist);
+}
+
 void maildir_uidlist_unlock(struct maildir_uidlist *uidlist)
 {
-	if (!UIDLIST_IS_LOCKED(uidlist))
+	i_assert(uidlist->lock_count > 0);
+
+	if (--uidlist->lock_count > 0)
 		return;
 
 	(void)file_dotlock_delete(&uidlist->dotlock);
@@ -517,7 +529,7 @@
 	const char *temp_path, *db_path;
 	int ret;
 
-	i_assert(UIDLIST_IS_LOCKED(uidlist));
+	i_assert(uidlist->lock_count == 1);
 
 	temp_path = t_strconcat(mbox->control_dir,
 				"/" MAILDIR_UIDLIST_NAME ".lock", NULL);
@@ -533,7 +545,9 @@
 			(void)unlink(temp_path);
 			ret = -1;
 		}
+
 		uidlist->lock_fd = -1;
+		uidlist->lock_count--;
 	} else {
                 maildir_uidlist_unlock(uidlist);
 	}

Index: maildir-uidlist.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-uidlist.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- maildir-uidlist.h	8 Apr 2005 13:13:47 -0000	1.13
+++ maildir-uidlist.h	30 Jun 2005 20:28:20 -0000	1.14
@@ -14,6 +14,7 @@
 int maildir_uidlist_lock(struct maildir_uidlist *uidlist);
 int maildir_uidlist_try_lock(struct maildir_uidlist *uidlist);
 void maildir_uidlist_unlock(struct maildir_uidlist *uidlist);
+int maildir_uidlist_is_locked(struct maildir_uidlist *uidlist);
 
 struct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox);
 void maildir_uidlist_deinit(struct maildir_uidlist *uidlist);

Index: maildir-util.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-util.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- maildir-util.c	9 Jun 2005 14:31:43 -0000	1.12
+++ maildir-util.c	30 Jun 2005 20:28:20 -0000	1.13
@@ -6,6 +6,7 @@
 #include "str.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
+#include "maildir-keywords.h"
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -63,130 +64,6 @@
 	return ret == -2 ? 0 : ret;
 }
 
-int maildir_filename_get_flags(const char *fname, pool_t pool,
-			       enum mail_flags *flags_r,
-			       const char *const **keywords_r)
-{
-	const char *info;
-	unsigned int num;
-
-	*flags_r = 0;
-	*keywords_r = NULL;
-
-	info = strchr(fname, MAILDIR_INFO_SEP);
-	if (info == NULL || info[1] != '2' || info[2] != MAILDIR_FLAGS_SEP)
-		return 0;
-
-	for (info += 3; *info != '\0' && *info != MAILDIR_FLAGS_SEP; info++) {
-		switch (*info) {
-		case 'R': /* replied */
-			*flags_r |= MAIL_ANSWERED;
-			break;
-		case 'S': /* seen */
-			*flags_r |= MAIL_SEEN;
-			break;
-		case 'T': /* trashed */
-			*flags_r |= MAIL_DELETED;
-			break;
-		case 'D': /* draft */
-			*flags_r |= MAIL_DRAFT;
-			break;
-		case 'F': /* flagged */
-			*flags_r |= MAIL_FLAGGED;
-			break;
-		default:
-			if (*info >= 'a' && *info <= 'z') {
-				/* FIXME: keyword */
-				num = (*info - 'a');
-				break;
-			}
-
-			/* unknown flag - ignore */
-			break;
-		}
-	}
-
-	return 1;
-}
-
-const char *maildir_filename_set_flags(const char *fname, enum mail_flags flags,
-				       const char *const *keywords)
-{
-	string_t *flags_str;
-	enum mail_flags flags_left;
-	const char *info, *oldflags;
-	int nextflag;
-
-	/* remove the old :info from file name, and get the old flags */
-	info = strrchr(fname, MAILDIR_INFO_SEP);
-	if (info != NULL && strrchr(fname, '/') > info)
-		info = NULL;
-
-	oldflags = "";
-	if (info != NULL) {
-		fname = t_strdup_until(fname, info);
-		if (info[1] == '2' && info[2] == MAILDIR_FLAGS_SEP)
-			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, MAILDIR_FLAGS_FULL_SEP);
-	flags_left = flags;
-	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 == MAILDIR_FLAGS_SEP ?
-			256 : (unsigned char) *oldflags;
-
-		if ((flags_left & MAIL_DRAFT) && nextflag > 'D') {
-			str_append_c(flags_str, 'D');
-			flags_left &= ~MAIL_DRAFT;
-		}
-		if ((flags_left & MAIL_FLAGGED) && nextflag > 'F') {
-			str_append_c(flags_str, 'F');
-			flags_left &= ~MAIL_FLAGGED;
-		}
-		if ((flags_left & MAIL_ANSWERED) && nextflag > 'R') {
-			str_append_c(flags_str, 'R');
-			flags_left &= ~MAIL_ANSWERED;
-		}
-		if ((flags_left & MAIL_SEEN) && nextflag > 'S') {
-			str_append_c(flags_str, 'S');
-			flags_left &= ~MAIL_SEEN;
-		}
-		if ((flags_left & MAIL_DELETED) && nextflag > 'T') {
-			str_append_c(flags_str, 'T');
-			flags_left &= ~MAIL_DELETED;
-		}
-
-		if (keywords != NULL && nextflag > 'a') {
-			// FIXME
-		}
-
-		if (*oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP)
-			break;
-
-		str_append_c(flags_str, *oldflags);
-		oldflags++;
-	}
-
-	if (*oldflags == MAILDIR_FLAGS_SEP) {
-		/* 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);
-}
-
 const char *maildir_generate_tmp_filename(const struct timeval *tv)
 {
 	static unsigned int create_count = 0;



More information about the dovecot-cvs mailing list