static int dsync_mailbox_tree_fix_guid_duplicate(struct dsync_mailbox_tree *tree, struct dsync_mailbox_node *node1, struct dsync_mailbox_node *node2) { struct mailbox *box; struct mailbox_update update; struct dsync_mailbox_node *change_node; const char *change_vname; int ret = 0; i_zero(&update); guid_128_generate(update.mailbox_guid); /* just in case the duplication exists in both sides, make them choose the same node */ if (strcmp(dsync_mailbox_node_get_full_name(tree, node1), dsync_mailbox_node_get_full_name(tree, node2)) <= 0) change_node = node1; else change_node = node2; change_vname = dsync_mailbox_node_get_full_name(tree, change_node); i_error("Duplicate mailbox GUID %s for mailboxes %s and %s - " "giving a new GUID %s to %s", guid_128_to_string(node1->mailbox_guid), dsync_mailbox_node_get_full_name(tree, node1), dsync_mailbox_node_get_full_name(tree, node2), guid_128_to_string(update.mailbox_guid), change_vname); i_assert(node1->ns != NULL && node2->ns != NULL); box = mailbox_alloc(change_node->ns->list, change_vname, 0); if (mailbox_update(box, &update) < 0) { i_error("Couldn't update mailbox %s GUID: %s", change_vname, mailbox_get_last_internal_error(box, NULL)); ret = -1; } else { memcpy(change_node->mailbox_guid, update.mailbox_guid, sizeof(change_node->mailbox_guid)); } mailbox_free(&box); return ret; }
void dsync_brain_mailbox_update_pre(struct dsync_brain *brain, struct mailbox *box, const struct dsync_mailbox *local_box, const struct dsync_mailbox *remote_box) { struct mailbox_update update; const struct dsync_mailbox_state *state; memset(&update, 0, sizeof(update)); if (local_box->uid_validity != remote_box->uid_validity) { /* Keep the UIDVALIDITY for the mailbox that has more messages. If they equal, use the higher UIDVALIDITY. */ if (remote_box->messages_count > local_box->messages_count || (remote_box->messages_count == local_box->messages_count && remote_box->uid_validity > local_box->uid_validity)) update.uid_validity = remote_box->uid_validity; state = dsync_mailbox_state_find(brain, local_box->mailbox_guid); if (state != NULL && state->last_common_uid > 0) { /* we can't continue syncing this mailbox in this session, because the other side already started sending mailbox changes, but not for all mails. */ dsync_mailbox_state_remove(brain, local_box->mailbox_guid); // FIXME: handle this properly } } dsync_cache_fields_update(local_box, remote_box, &update); if (update.uid_validity == 0 && update.cache_updates == NULL) { /* no changes */ return; } if (mailbox_update(box, &update) < 0) { i_error("Couldn't update mailbox %s metadata: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); brain->failed = TRUE; } }
static int sync_create_box(struct dsync_brain *brain, struct mailbox *box, const guid_128_t mailbox_guid, uint32_t uid_validity, enum mail_error *error_r) { struct mailbox_metadata metadata; struct mailbox_update update; enum mail_error error; const char *errstr; int ret; memset(&update, 0, sizeof(update)); memcpy(update.mailbox_guid, mailbox_guid, sizeof(update.mailbox_guid)); update.uid_validity = uid_validity; if (mailbox_create(box, &update, FALSE) < 0) { errstr = mailbox_get_last_error(box, &error); if (error != MAIL_ERROR_EXISTS) { i_error("Can't create mailbox %s: %s", mailbox_get_vname(box), errstr); *error_r = error; return -1; } } if (brain->no_mail_sync) { /* trust that create worked, we can't actually open it and verify. */ return 0; } /* sync the mailbox so we can look up its latest status */ if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Can't sync mailbox %s: %s", mailbox_get_vname(box), mailbox_get_last_error(box, error_r)); return -1; } /* verify that the GUID is what we wanted. if it's not, it probably means that the mailbox had already been created. then we'll use the GUID that is higher. mismatching UIDVALIDITY is handled later, because we choose it by checking which mailbox has more messages */ if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) { i_error("Can't get mailbox GUID %s: %s", mailbox_get_vname(box), mailbox_get_last_error(box, error_r)); return -1; } ret = memcmp(mailbox_guid, metadata.guid, sizeof(metadata.guid)); if (ret > 0) { if (brain->debug) { i_debug("brain %c: Changing mailbox %s GUID %s -> %s", brain->master_brain ? 'M' : 'S', mailbox_get_vname(box), guid_128_to_string(metadata.guid), guid_128_to_string(mailbox_guid)); } memset(&update, 0, sizeof(update)); memcpy(update.mailbox_guid, mailbox_guid, sizeof(update.mailbox_guid)); if (mailbox_update(box, &update) < 0) { i_error("Can't update mailbox GUID %s: %s", mailbox_get_vname(box), mailbox_get_last_error(box, error_r)); return -1; } /* verify that the update worked */ if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) { i_error("Can't get mailbox GUID %s: %s", mailbox_get_vname(box), mailbox_get_last_error(box, error_r)); return -1; } if (memcmp(mailbox_guid, metadata.guid, sizeof(metadata.guid)) != 0) { i_error("Backend didn't update mailbox %s GUID", mailbox_get_vname(box)); *error_r = MAIL_ERROR_TEMP; return -1; } } else if (ret < 0) { if (brain->debug) { i_debug("brain %c: Other brain should change mailbox " "%s GUID %s -> %s", brain->master_brain ? 'M' : 'S', mailbox_get_vname(box), guid_128_to_string(mailbox_guid), guid_128_to_string(metadata.guid)); } } return 0; }