diff src/dsync/dsync-brain.c @ 9638:b11a3eda2477 HEAD

dsync: Use expunged messages' GUIDs to determine what to do with missing messages at end of mailbox. If GUIDs match, expunge the message. If they don't match, treat it as UID conflict.
author Timo Sirainen <tss@iki.fi>
date Wed, 15 Jul 2009 18:31:59 -0400
parents 7b0bcf423fca
children ffda7bd92ebc
line wrap: on
line diff
--- a/src/dsync/dsync-brain.c	Wed Jul 15 18:29:58 2009 -0400
+++ b/src/dsync/dsync-brain.c	Wed Jul 15 18:31:59 2009 -0400
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "hash.h"
+#include "hex-binary.h"
 #include "master-service.h"
 #include "dsync-worker.h"
 #include "dsync-brain-private.h"
@@ -216,48 +217,91 @@
 		dsync_worker_msg_update_metadata(brain->dest_worker, src_msg);
 }
 
+static const char *
+get_guid_128_str(const char *guid, unsigned char *dest, unsigned int dest_len)
+{
+	uint8_t guid_128[MAIL_GUID_128_SIZE];
+	buffer_t guid_128_buf;
+
+	buffer_create_data(&guid_128_buf, dest, dest_len);
+	mail_generate_guid_128_hash(guid, guid_128);
+	binary_to_hex_append(&guid_128_buf, guid_128, sizeof(guid_128));
+	buffer_append_c(&guid_128_buf, '\0');
+	return guid_128_buf.data;
+}
+
 static int dsync_brain_msg_sync_pair(struct dsync_brain_mailbox_sync *sync)
 {
 	struct dsync_message *src_msg = &sync->src_msg_iter->msg;
 	struct dsync_message *dest_msg = &sync->dest_msg_iter->msg;
 	struct dsync_mailbox *const *boxp;
 	struct dsync_brain_uid_conflict *conflict;
+	const char *src_guid, *dest_guid;
+	unsigned char guid_128_data[MAIL_GUID_128_SIZE * 2 + 1];
+	bool src_expunged, dest_expunged;
+
+	src_expunged = (src_msg->flags & DSYNC_MAIL_FLAG_EXPUNGED) != 0;
+	dest_expunged = (dest_msg->flags & DSYNC_MAIL_FLAG_EXPUNGED) != 0;
+
+	if (src_expunged) {
+		src_guid = src_msg->guid;
+		dest_guid = get_guid_128_str(dest_msg->guid, guid_128_data,
+					     sizeof(guid_128_data));
+	} else if (dest_expunged) {
+		src_guid = get_guid_128_str(src_msg->guid, guid_128_data,
+					    sizeof(guid_128_data));
+		dest_guid = dest_msg->guid;
+	} else {
+		src_guid = src_msg->guid;
+		dest_guid = dest_msg->guid;
+	}
 
 	if (src_msg->uid < dest_msg->uid) {
 		/* message has been expunged from dest. ignore it, unless
 		   we're in uid-conflict mode. */
-		if (sync->uid_conflict)
+		if (sync->uid_conflict && !src_expunged)
 			dsync_brain_msg_sync_save_source(sync);
 		src_msg->guid = NULL;
+		return 0;
 	} else if (src_msg->uid > dest_msg->uid) {
 		/* message has been expunged from src. expunge it from dest
 		   too, unless we're in uid-conflict mode. */
-		if (!sync->uid_conflict) {
+		if (!sync->uid_conflict && !dest_expunged) {
 			dsync_worker_msg_expunge(sync->brain->dest_worker,
 						 dest_msg->uid);
 		}
 		dest_msg->guid = NULL;
-	} else if (strcmp(src_msg->guid, dest_msg->guid) == 0) {
-		/* message exists, sync metadata */
-		dsync_brain_msg_sync_existing(sync->brain, src_msg, dest_msg);
-		src_msg->guid = NULL;
-		dest_msg->guid = NULL;
-	} else {
-		/* UID conflict. change UID in destination */
+		return 0;
+	}
+
+	/* UIDs match, but do GUIDs? */
+	if (strcmp(src_guid, dest_guid) != 0) {
+		/* UID conflict. give new UIDs to messages in both src and
+		   dest (if they're not expunged already) */
 		sync->uid_conflict = TRUE;
-		conflict = array_append_space(&sync->uid_conflicts);
-		conflict->mailbox_idx = sync->src_msg_iter->mailbox_idx;
-		conflict->uid = dest_msg->uid;
-
-		/* give new UID for the source message message too. */
-		boxp = array_idx(&sync->brain->src_mailbox_list->mailboxes,
-				 conflict->mailbox_idx);
-		src_msg->uid = (*boxp)->uid_next++;
-
-		dsync_brain_msg_sync_save_source(sync);
-		src_msg->guid = NULL;
-		dest_msg->guid = NULL;
+		if (!dest_expunged) {
+			conflict = array_append_space(&sync->uid_conflicts);
+			conflict->mailbox_idx = sync->src_msg_iter->mailbox_idx;
+			conflict->uid = dest_msg->uid;
+		}
+		if (!src_expunged) {
+			boxp = array_idx(&sync->brain->src_mailbox_list->mailboxes,
+					 conflict->mailbox_idx);
+			src_msg->uid = (*boxp)->uid_next++;
+			dsync_brain_msg_sync_save_source(sync);
+		}
+	} else if (dest_expunged) {
+		/* message expunged from destination, we can skip this. */
+	} else if (src_expunged) {
+		/* message expunged from source, expunge from destination too */
+		dsync_worker_msg_expunge(sync->brain->dest_worker,
+					 dest_msg->uid);
+	} else {
+		/* message exists in both source and dest, sync metadata */
+		dsync_brain_msg_sync_existing(sync->brain, src_msg, dest_msg);
 	}
+	src_msg->guid = NULL;
+	dest_msg->guid = NULL;
 	return 0;
 }