diff src/lib-index/maildir/maildir-index.c @ 0:3b1985cbc908 HEAD

Initial revision
author Timo Sirainen <tss@iki.fi>
date Fri, 09 Aug 2002 12:15:38 +0300
parents
children 1b34ec11fff8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-index/maildir/maildir-index.c	Fri Aug 09 12:15:38 2002 +0300
@@ -0,0 +1,182 @@
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "lib.h"
+#include "maildir-index.h"
+#include "mail-index-util.h"
+
+#include <stdio.h>
+
+static MailIndex maildir_index;
+
+const char *maildir_filename_set_flags(const char *fname, MailFlags flags)
+{
+	const char *info, *oldflags;
+	char *flags_buf, *p;
+	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_strndup(fname, (unsigned int) (info-fname));
+		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_buf = t_malloc(MAIL_FLAGS_COUNT+strlen(oldflags)+1);
+	p = flags_buf;
+
+	for (;;) {
+		/* skip all known flags */
+		while (*oldflags == 'D' || *oldflags == 'F' ||
+		       *oldflags == 'R' || *oldflags == 'S' ||
+		       *oldflags == 'T' ||
+		       (*oldflags >= 'a' && *oldflags <= 'z'))
+			oldflags++;
+
+		nextflag = *oldflags == '\0' ? 256 :
+			(unsigned char) *oldflags;
+
+		if ((flags & MAIL_DRAFT) && nextflag > 'D') {
+			*p++ = 'D';
+			flags &= ~MAIL_DRAFT;
+		}
+		if ((flags & MAIL_FLAGGED) && nextflag > 'F') {
+			*p++ = 'F';
+			flags &= ~MAIL_FLAGGED;
+		}
+		if ((flags & MAIL_ANSWERED) && nextflag > 'R') {
+			*p++ = 'R';
+			flags &= ~MAIL_ANSWERED;
+		}
+		if ((flags & MAIL_SEEN) && nextflag > 'S') {
+			*p++ = 'S';
+			flags &= ~MAIL_SEEN;
+		}
+		if ((flags & MAIL_DELETED) && nextflag > 'T') {
+			*p++ = '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)))
+					*p++ = 'a' + i;
+			}
+			flags &= ~MAIL_CUSTOM_FLAGS_MASK;
+		}
+
+		if (*oldflags == '\0')
+			break;
+
+		*p++ = *oldflags++;
+	}
+
+	*p = '\0';
+
+	return t_strconcat(fname, ":2,", flags_buf, NULL);
+}
+
+MailIndex *maildir_index_alloc(const char *dir)
+{
+	MailIndex *index;
+	int len;
+
+	i_assert(dir != NULL);
+
+	index = i_new(MailIndex, 1);
+	memcpy(index, &maildir_index, sizeof(MailIndex));
+
+	index->fd = -1;
+	index->dir = i_strdup(dir);
+
+	len = strlen(index->dir);
+	if (index->dir[len-1] == '/')
+		index->dir[len-1] = '\0';
+
+	return (MailIndex *) index;
+}
+
+static void maildir_index_free(MailIndex *index)
+{
+	mail_index_close(index);
+	i_free(index->dir);
+	i_free(index);
+}
+
+static int maildir_index_update_flags(MailIndex *index, MailIndexRecord *rec,
+				      unsigned int seq, MailFlags flags,
+				      int external_change)
+{
+	MailIndexUpdate *update;
+	const char *old_fname, *new_fname;
+	const char *old_path, *new_path;
+
+	if (!mail_index_update_flags(index, rec, seq, flags, external_change))
+		return FALSE;
+
+	/* we need to update the flags in the file name */
+	old_fname = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
+	if (old_fname == NULL) {
+                INDEX_MARK_CORRUPTED(index);
+		index_set_error(index, "Corrupted index file %s: "
+				"Missing location field for record %u",
+				index->filepath, rec->uid);
+		return FALSE;
+	}
+
+	new_fname = maildir_filename_set_flags(old_fname, flags);
+
+	if (strcmp(old_fname, new_fname) != 0) {
+		old_path = t_strconcat(index->dir, "/cur/", old_fname, NULL);
+		new_path = t_strconcat(index->dir, "/cur/", new_fname, NULL);
+
+		/* minor problem: new_path is overwritten if it exists.. */
+		if (rename(old_path, new_path) == -1) {
+			index_set_error(index, "maildir flags update: "
+					"rename(%s, %s) failed: %m",
+					old_path, new_path);
+			return FALSE;
+		}
+
+		/* update the filename in index */
+		update = index->update_begin(index, rec);
+		index->update_field(update, FIELD_TYPE_LOCATION, new_fname, 0);
+
+		if (!index->update_end(update))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static MailIndex maildir_index = {
+	mail_index_open,
+	mail_index_open_or_create,
+	maildir_index_free,
+	mail_index_set_lock,
+	mail_index_try_lock,
+	maildir_index_rebuild,
+	mail_index_fsck,
+	maildir_index_sync,
+	mail_index_get_header,
+	mail_index_lookup,
+	mail_index_next,
+        mail_index_lookup_uid_range,
+	mail_index_lookup_field,
+	mail_index_get_sequence,
+	maildir_open_mail,
+	mail_index_expunge,
+	maildir_index_update_flags,
+	mail_index_append,
+	mail_index_update_begin,
+	mail_index_update_end,
+	mail_index_update_field,
+	mail_index_get_last_error,
+	mail_index_is_inconsistency_error
+};