dovecot-1.0: Support reading dovecot-uidlist version 3, although...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jul 12 04:22:58 EEST 2007


details:   http://hg.dovecot.org/dovecot-1.0/rev/a948df958d10
changeset: 5342:a948df958d10
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jul 12 04:22:51 2007 +0300
description:
Support reading dovecot-uidlist version 3, although all extensions are just
ignored. Dovecot v1.1 creates them.

diffstat:

1 file changed, 119 insertions(+), 31 deletions(-)
src/lib-storage/index/maildir/maildir-uidlist.c |  150 ++++++++++++++++++-----

diffs (218 lines):

diff -r b6753fd66298 -r a948df958d10 src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Thu Jul 12 04:10:42 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Thu Jul 12 04:22:51 2007 +0300
@@ -222,6 +222,7 @@ static int maildir_uidlist_next(struct m
 static int maildir_uidlist_next(struct maildir_uidlist *uidlist,
 				const char *line)
 {
+	struct mail_storage *storage = STORAGE(uidlist->mbox->storage);
         struct maildir_uidlist_rec *rec;
 	uint32_t uid, flags;
 
@@ -233,12 +234,12 @@ static int maildir_uidlist_next(struct m
 
 	if (uid == 0 || *line != ' ') {
 		/* invalid file */
-                mail_storage_set_critical(STORAGE(uidlist->mbox->storage),
+                mail_storage_set_critical(storage,
 			"Invalid data in file %s", uidlist->fname);
 		return 0;
 	}
 	if (uid <= uidlist->prev_read_uid) {
-                mail_storage_set_critical(STORAGE(uidlist->mbox->storage),
+                mail_storage_set_critical(storage,
 			"UIDs not ordered in file %s (%u > %u)",
 			uidlist->fname, uid, uidlist->prev_read_uid);
 		return 0;
@@ -251,8 +252,8 @@ static int maildir_uidlist_next(struct m
 	}
         uidlist->last_seen_uid = uid;
 
-	if (uid >= uidlist->next_uid) {
-                mail_storage_set_critical(STORAGE(uidlist->mbox->storage),
+	if (uid >= uidlist->next_uid && uidlist->version == 1) {
+		mail_storage_set_critical(storage,
 			"UID larger than next_uid in file %s (%u >= %u)",
 			uidlist->fname, uid, uidlist->next_uid);
 		return 0;
@@ -260,14 +261,30 @@ static int maildir_uidlist_next(struct m
 
 	while (*line == ' ') line++;
 
-	if (uidlist->version == 2) {
+	switch (uidlist->version) {
+	case 2:
 		/* skip flags parameter */
 		while (*line != ' ') line++;
 		while (*line == ' ') line++;
+		break;
+	case 3:
+		/* skip extended fields. filename begins from  */
+		if (*line == ':')
+			line++;
+		else {
+			line = strstr(line, " :");
+			if (line != NULL)
+				line += 2;
+		}
+		if (line == NULL || *line == '\0') {
+			mail_storage_set_critical(storage,
+				"Invalid data in file %s", uidlist->fname);
+			return 0;
+		}
 	}
 
 	if (hash_lookup_full(uidlist->files, line, NULL, NULL)) {
-                mail_storage_set_critical(STORAGE(uidlist->mbox->storage),
+                mail_storage_set_critical(storage,
 			"Duplicate file in uidlist file %s: %s",
 			uidlist->fname, line);
 		return 0;
@@ -282,13 +299,96 @@ static int maildir_uidlist_next(struct m
 	return 1;
 }
 
+static int maildir_uidlist_read_header(struct maildir_uidlist *uidlist,
+				       struct istream *input)
+{
+	struct mail_storage *storage = STORAGE(uidlist->mbox->storage);
+	unsigned int uid_validity, next_uid;
+	const char *line, *value;
+	char key;
+
+	line = i_stream_read_next_line(input);
+        if (line == NULL) {
+                /* I/O error / empty file */
+                return input->stream_errno == 0 ? 0 : -1;
+	}
+
+	if (*line < '0' || *line > '9' || line[1] != ' ') {
+		mail_storage_set_critical(storage,
+			"%s: Corrupted header (invalid version number)",
+			uidlist->fname);
+		return 0;
+	}
+
+	uidlist->version = *line - '0';
+	line += 2;
+
+	switch (uidlist->version) {
+	case 1:
+	case 2:
+		if (sscanf(line, "%u %u", &uid_validity, &next_uid) != 2) {
+			mail_storage_set_critical(storage,
+				"%s: Corrupted header (version 1)",
+				uidlist->fname);
+			return 0;
+		}
+		if (uid_validity == uidlist->uid_validity &&
+		    next_uid < uidlist->next_uid) {
+			mail_storage_set_critical(storage,
+				"%s: next_uid was lowered (%u -> %u)",
+				uidlist->fname, uidlist->next_uid, next_uid);
+			return 0;
+		}
+		break;
+	case 3:
+		while (*line != '\0') {
+			t_push();
+			key = *line;
+			value = ++line;
+			while (*line != '\0' && *line != ' ') line++;
+			value = t_strdup_until(value, line);
+
+			switch (key) {
+			case 'V':
+				uid_validity = strtoul(value, NULL, 10);
+				break;
+			case 'N':
+				next_uid = strtoul(value, NULL, 10);
+				break;
+			default:
+				/* ignore the rest */
+				break;
+			}
+
+			while (*line == ' ') line++;
+			t_pop();
+		}
+		break;
+	default:
+		mail_storage_set_critical(storage, "%s: Unsupported version %u",
+					  uidlist->fname, uidlist->version);
+		return 0;
+	}
+
+	if (uid_validity == 0 || next_uid == 0) {
+		mail_storage_set_critical(storage,
+			"%s: Broken header (uidvalidity = %u, next_uid=%u)",
+			uidlist->fname, uid_validity, next_uid);
+		return 0;
+	}
+
+	uidlist->uid_validity = uid_validity;
+	uidlist->next_uid = next_uid;
+	return 1;
+}
+
 static int
 maildir_uidlist_update_read(struct maildir_uidlist *uidlist,
 			    bool *retry_r, bool try_retry)
 {
 	struct mail_storage *storage = STORAGE(uidlist->mbox->storage);
 	const char *line;
-	unsigned int uid_validity, next_uid;
+	unsigned int uid_validity, next_uid, orig_next_uid;
 	struct istream *input;
 	struct stat st;
 	int fd, ret;
@@ -329,30 +429,8 @@ maildir_uidlist_update_read(struct maild
 	input = i_stream_create_file(fd, default_pool, 4096, TRUE);
 
 	/* get header */
-	line = i_stream_read_next_line(input);
-        if (line == NULL) {
-                /* I/O error / empty file */
-                ret = input->stream_errno == 0 ? 0 : -1;
-        } else if (sscanf(line, "%u %u %u", &uidlist->version,
-                          &uid_validity, &next_uid) != 3 ||
-                   uidlist->version < 1 || uidlist->version > 2) {
-                /* broken file */
-                mail_storage_set_critical(storage,
-			"Corrupted header in file %s (version = %u)",
-			uidlist->fname, uidlist->version);
-		ret = 0;
-	} else if (uid_validity == uidlist->uid_validity &&
-		   next_uid < uidlist->next_uid) {
-                mail_storage_set_critical(storage,
-			"%s: next_uid was lowered (%u -> %u)",
-			uidlist->fname, uidlist->next_uid, next_uid);
-		ret = 0;
-	} else if (uid_validity == 0 || next_uid == 0) {
-                mail_storage_set_critical(storage,
-			"%s: Broken header (uidvalidity = %u, next_uid=%u)",
-			uidlist->fname, uid_validity, next_uid);
-		ret = 0;
-	} else {
+	if ((ret = maildir_uidlist_read_header(uidlist, input)) > 0) {
+		orig_next_uid = next_uid;
 		uidlist->uid_validity = uid_validity;
 		uidlist->next_uid = next_uid;
 		uidlist->prev_read_uid = 0;
@@ -366,6 +444,16 @@ maildir_uidlist_update_read(struct maild
                 }
                 if (input->stream_errno != 0)
                         ret = -1;
+
+		if (uidlist->next_uid <= uidlist->prev_read_uid)
+			uidlist->next_uid = uidlist->prev_read_uid + 1;
+		if (uidlist->next_uid < orig_next_uid) {
+			mail_storage_set_critical(storage,
+				"%s: next_uid was lowered (%u -> %u)",
+				uidlist->fname, orig_next_uid,
+				uidlist->next_uid);
+			uidlist->next_uid = orig_next_uid;
+		}
 	}
 
         if (ret == 0) {


More information about the dovecot-cvs mailing list