# --- SDE-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # Filename: package/.../dovecot/dovecot-2.2.2-0000-upstream-fixes.patch # Copyright (C) 2013 The OpenSDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- SDE-COPYRIGHT-NOTE-END --- From 5dcc6d180aec16d34d60719248a17ec026425fa8 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 20 May 2013 17:30:23 +0300 Subject: [PATCH] dsync: Fixed unsubscribing from an already deleted mailbox. diff --git a/src/doveadm/dsync/dsync-brain-mailbox-tree.c b/src/doveadm/dsync/dsync-brain-mailbox-tree.c index 6c878da..6354038 100644 --- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c @@ -371,11 +371,24 @@ dsync_brain_mailbox_tree_add_delete(struct dsync_mailbox_tree *tree, if (node == NULL) return; - if (!other_del->delete_mailbox && - other_del->timestamp <= node->last_renamed_or_created) { - /* we don't want to delete this directory, we already have a - newer timestamp for it */ - return; + switch (other_del->type) { + case DSYNC_MAILBOX_DELETE_TYPE_MAILBOX: + /* mailbox is always deleted */ + break; + case DSYNC_MAILBOX_DELETE_TYPE_DIR: + if (other_del->timestamp <= node->last_renamed_or_created) { + /* we don't want to delete this directory, we already + have a newer timestamp for it */ + return; + } + break; + case DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE: + if (other_del->timestamp <= node->last_subscription_change) { + /* we don't want to unsubscribe, since we already have + a newer subscription timestamp */ + return; + } + break; } /* make a node for it in the other mailbox tree */ @@ -384,20 +397,25 @@ dsync_brain_mailbox_tree_add_delete(struct dsync_mailbox_tree *tree, if (!guid_128_is_empty(other_node->mailbox_guid) || (other_node->existence == DSYNC_MAILBOX_NODE_EXISTS && - !other_del->delete_mailbox)) { + other_del->type != DSYNC_MAILBOX_DELETE_TYPE_MAILBOX)) { /* other side has already created a new mailbox or directory with this name, we can't delete it */ return; } /* ok, mark the other node deleted */ - if (other_del->delete_mailbox) { + if (other_del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) { memcpy(other_node->mailbox_guid, node->mailbox_guid, sizeof(other_node->mailbox_guid)); } i_assert(other_node->ns == NULL || other_node->ns == node->ns); other_node->ns = node->ns; - other_node->existence = DSYNC_MAILBOX_NODE_DELETED; + if (other_del->type != DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE) + other_node->existence = DSYNC_MAILBOX_NODE_DELETED; + else { + other_node->last_subscription_change = other_del->timestamp; + other_node->subscribed = FALSE; + } if (dsync_mailbox_tree_guid_hash_add(other_tree, other_node, &old_node) < 0) diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c index 729a972..462815a 100644 --- a/src/doveadm/dsync/dsync-ibc-stream.c +++ b/src/doveadm/dsync/dsync-ibc-stream.c @@ -90,7 +90,7 @@ static const struct { { .name = "mailbox_delete", .chr = 'D', .required_keys = "hierarchy_sep", - .optional_keys = "mailboxes dirs" + .optional_keys = "mailboxes dirs unsubscribes" }, { .name = "mailbox", .chr = 'B', @@ -936,6 +936,28 @@ dsync_ibc_stream_recv_mailbox_tree_node(struct dsync_ibc *_ibc, } static void +dsync_ibc_stream_encode_delete(string_t *str, + struct dsync_serializer_encoder *encoder, + const struct dsync_mailbox_delete *deletes, + unsigned int count, const char *key, + enum dsync_mailbox_delete_type type) +{ + unsigned int i; + + str_truncate(str, 0); + for (i = 0; i < count; i++) { + if (deletes[i].type == type) { + str_append(str, guid_128_to_string(deletes[i].guid)); + str_printfa(str, " %ld ", (long)deletes[i].timestamp); + } + } + if (str_len(str) > 0) { + str_truncate(str, str_len(str)-1); + dsync_serializer_encode_add(encoder, key, str_c(str)); + } +} + +static void dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, const struct dsync_mailbox_delete *deletes, unsigned int count, char hierarchy_sep) @@ -944,7 +966,6 @@ dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, struct dsync_serializer_encoder *encoder; string_t *str, *substr; char sep[2]; - unsigned int i; str = t_str_new(128); str_append_c(str, items[ITEM_MAILBOX_DELETE].chr); @@ -954,29 +975,15 @@ dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, dsync_serializer_encode_add(encoder, "hierarchy_sep", sep); substr = t_str_new(128); - for (i = 0; i < count; i++) { - if (deletes[i].delete_mailbox) { - str_append(substr, guid_128_to_string(deletes[i].guid)); - str_printfa(substr, " %ld ", (long)deletes[i].timestamp); - } - } - if (str_len(substr) > 0) { - str_truncate(substr, str_len(substr)-1); - dsync_serializer_encode_add(encoder, "mailboxes", - str_c(substr)); - } - - str_truncate(substr, 0); - for (i = 0; i < count; i++) { - if (!deletes[i].delete_mailbox) { - str_append(substr, guid_128_to_string(deletes[i].guid)); - str_printfa(substr, " %ld ", (long)deletes[i].timestamp); - } - } - if (str_len(substr) > 0) { - str_truncate(substr, str_len(substr)-1); - dsync_serializer_encode_add(encoder, "dirs", str_c(substr)); - } + dsync_ibc_stream_encode_delete(substr, encoder, deletes, count, + "mailboxes", + DSYNC_MAILBOX_DELETE_TYPE_MAILBOX); + dsync_ibc_stream_encode_delete(substr, encoder, deletes, count, + "dirs", + DSYNC_MAILBOX_DELETE_TYPE_DIR); + dsync_ibc_stream_encode_delete(substr, encoder, deletes, count, + "unsubscribes", + DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE); dsync_serializer_encode_finish(&encoder, str); dsync_ibc_stream_send_string(ibc, str); } @@ -984,7 +991,7 @@ dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, ARRAY_DEFINE_TYPE(dsync_mailbox_delete, struct dsync_mailbox_delete); static int decode_mailbox_deletes(ARRAY_TYPE(dsync_mailbox_delete) *deletes, - const char *value, bool delete_mailbox) + const char *value, enum dsync_mailbox_delete_type type) { struct dsync_mailbox_delete *del; const char *const *tmp; @@ -993,7 +1000,7 @@ decode_mailbox_deletes(ARRAY_TYPE(dsync_mailbox_delete) *deletes, tmp = t_strsplit(value, " "); for (i = 0; tmp[i] != NULL; i += 2) { del = array_append_space(deletes); - del->delete_mailbox = delete_mailbox; + del->type = type; if (guid_128_from_string(tmp[i], del->guid) < 0) return -1; if (tmp[i+1] == NULL || @@ -1029,12 +1036,20 @@ dsync_ibc_stream_recv_mailbox_deletes(struct dsync_ibc *_ibc, *hierarchy_sep_r = value[0]; if (dsync_deserializer_decode_try(decoder, "mailboxes", &value) && - decode_mailbox_deletes(&deletes, value, TRUE) < 0) { + decode_mailbox_deletes(&deletes, value, + DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) < 0) { dsync_ibc_input_error(ibc, decoder, "Invalid mailboxes"); return DSYNC_IBC_RECV_RET_TRYAGAIN; } if (dsync_deserializer_decode_try(decoder, "dirs", &value) && - decode_mailbox_deletes(&deletes, value, FALSE) < 0) { + decode_mailbox_deletes(&deletes, value, + DSYNC_MAILBOX_DELETE_TYPE_DIR) < 0) { + dsync_ibc_input_error(ibc, decoder, "Invalid dirs"); + return DSYNC_IBC_RECV_RET_TRYAGAIN; + } + if (dsync_deserializer_decode_try(decoder, "unsubscribes", &value) && + decode_mailbox_deletes(&deletes, value, + DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE) < 0) { dsync_ibc_input_error(ibc, decoder, "Invalid dirs"); return DSYNC_IBC_RECV_RET_TRYAGAIN; } diff --git a/src/doveadm/dsync/dsync-mailbox-tree-fill.c b/src/doveadm/dsync/dsync-mailbox-tree-fill.c index ddf2ebb..9480ebb 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c +++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c @@ -163,7 +163,7 @@ dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, break; } del = array_append_space(&tree->deletes); - del->delete_mailbox = TRUE; + del->type = DSYNC_MAILBOX_DELETE_TYPE_MAILBOX; del->timestamp = timestamp; memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); break; @@ -177,6 +177,7 @@ dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, dsync side, it can match this deletion to the name. */ del = array_append_space(&tree->deletes); + del->type = DSYNC_MAILBOX_DELETE_TYPE_DIR; del->timestamp = timestamp; memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); break; @@ -195,10 +196,22 @@ dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, node->last_renamed_or_created = timestamp; break; case MAILBOX_LOG_RECORD_SUBSCRIBE: - case MAILBOX_LOG_RECORD_UNSUBSCRIBE: if (node != NULL) node->last_subscription_change = timestamp; break; + case MAILBOX_LOG_RECORD_UNSUBSCRIBE: + if (node != NULL) { + node->last_subscription_change = timestamp; + break; + } + /* The mailbox is already deleted, but it may still + exist on the other side (even the subscription + alone). */ + del = array_append_space(&tree->deletes); + del->type = DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE; + del->timestamp = timestamp; + memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); + break; } } if (mailbox_log_iter_deinit(&iter) < 0) { diff --git a/src/doveadm/dsync/dsync-mailbox-tree.c b/src/doveadm/dsync/dsync-mailbox-tree.c index 0fa036d..cd8aa9f 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-mailbox-tree.c @@ -359,7 +359,7 @@ dsync_mailbox_tree_find_delete(struct dsync_mailbox_tree *tree, i_assert(hash_table_is_created(tree->guid_hash)); i_assert(tree->remote_sep != '\0'); - if (del->delete_mailbox) { + if (del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) { /* find node by GUID */ return hash_table_lookup(tree->guid_hash, guid_p); } diff --git a/src/doveadm/dsync/dsync-mailbox-tree.h b/src/doveadm/dsync/dsync-mailbox-tree.h index 58e4531..5a84b0e 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree.h +++ b/src/doveadm/dsync/dsync-mailbox-tree.h @@ -63,10 +63,17 @@ ARRAY_DEFINE_TYPE(dsync_mailbox_node, struct dsync_mailbox_node *); #define dsync_mailbox_node_is_dir(node) \ guid_128_is_empty((node)->mailbox_guid) +enum dsync_mailbox_delete_type { + /* Delete mailbox by given GUID */ + DSYNC_MAILBOX_DELETE_TYPE_MAILBOX = 1, + /* Delete mailbox directory by given SHA1 name */ + DSYNC_MAILBOX_DELETE_TYPE_DIR, + /* Unsubscribe mailbox by given SHA1 name */ + DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE, +}; + struct dsync_mailbox_delete { - /* true: guid = mailbox GUID - false: guid = sha1 of directory name */ - bool delete_mailbox; + enum dsync_mailbox_delete_type type; guid_128_t guid; time_t timestamp; }; -- 1.7.10.2 From 25c76e24f77e4f66cdbc3a60be390bbeb2230c9c Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 20 May 2013 18:26:16 +0300 Subject: [PATCH] dsync: Previous have_save_guids change somewhat broke compatibility with earlier dsync versions. diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c index 462815a..3dab919 100644 --- a/src/doveadm/dsync/dsync-ibc-stream.c +++ b/src/doveadm/dsync/dsync-ibc-stream.c @@ -28,10 +28,11 @@ #define DSYNC_IBC_STREAM_OUTBUF_THROTTLE_SIZE (1024*128) #define DSYNC_PROTOCOL_VERSION_MAJOR 3 -#define DSYNC_PROTOCOL_VERSION_MINOR 1 +#define DSYNC_PROTOCOL_VERSION_MINOR 2 #define DSYNC_HANDSHAKE_VERSION "VERSION\tdsync\t3\t1\n" #define DSYNC_PROTOCOL_MINOR_HAVE_ATTRIBUTES 1 +#define DSYNC_PROTOCOL_MINOR_HAVE_SAVE_GUID 2 enum item_type { ITEM_NONE, @@ -1227,7 +1228,8 @@ dsync_ibc_stream_recv_mailbox(struct dsync_ibc *_ibc, box->mailbox_lost = TRUE; if (dsync_deserializer_decode_try(decoder, "have_guids", &value)) box->have_guids = TRUE; - if (dsync_deserializer_decode_try(decoder, "have_save_guids", &value)) + if (dsync_deserializer_decode_try(decoder, "have_save_guids", &value) || + (box->have_guids && ibc->minor_version < DSYNC_PROTOCOL_MINOR_HAVE_SAVE_GUID)) box->have_save_guids = TRUE; value = dsync_deserializer_decode_get(decoder, "uid_validity"); if (str_to_uint32(value, &box->uid_validity) < 0) { -- 1.7.10.2