bool dsync_brain_slave_recv_mailbox(struct dsync_brain *brain)
{
	const struct dsync_mailbox *dsync_box;
	struct dsync_mailbox local_dsync_box;
	struct mailbox *box;
	const char *error;
	int ret;

	i_assert(!brain->master_brain);
	i_assert(brain->box == NULL);

	if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0)
		return FALSE;
	if (ret < 0) {
		brain->state = DSYNC_STATE_DONE;
		return TRUE;
	}

	if (dsync_brain_mailbox_alloc(brain, dsync_box->mailbox_guid,
				      &box, &error) < 0) {
		i_error("Couldn't allocate mailbox GUID %s: %s",
			guid_128_to_string(dsync_box->mailbox_guid), error);
		i_assert(brain->failed);
		return TRUE;
	}
	if (box == NULL) {
		/* mailbox was probably deleted/renamed during sync */
		if (brain->backup_send && brain->no_backup_overwrite) {
			if (brain->debug) {
				i_debug("brain %c: Ignore nonexistent "
					"mailbox GUID %s with -1 sync",
					brain->master_brain ? 'M' : 'S',
					guid_128_to_string(dsync_box->mailbox_guid));
			}
			dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
			return TRUE;
		}
		//FIXME: verify this from log, and if not log an error.
		if (brain->debug) {
			i_debug("brain %c: Change during sync: "
				"Mailbox GUID %s was lost",
				brain->master_brain ? 'M' : 'S',
				guid_128_to_string(dsync_box->mailbox_guid));
		}
		brain->changes_during_sync = TRUE;
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	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, NULL));
		mailbox_free(&box);
		brain->failed = TRUE;
		return TRUE;
	}

	if ((ret = dsync_box_get(box, &local_dsync_box)) <= 0) {
		mailbox_free(&box);
		if (ret < 0) {
			brain->failed = TRUE;
			return TRUE;
		}
		/* another process just deleted this mailbox? */
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	i_assert(local_dsync_box.uid_validity != 0);
	i_assert(memcmp(dsync_box->mailbox_guid, local_dsync_box.mailbox_guid,
			sizeof(dsync_box->mailbox_guid)) == 0);
	dsync_ibc_send_mailbox(brain->ibc, &local_dsync_box);

	dsync_brain_mailbox_update_pre(brain, box, &local_dsync_box, dsync_box);

	if (!dsync_boxes_need_sync(brain, &local_dsync_box, dsync_box)) {
		/* no fields appear to have changed, skip this mailbox */
		mailbox_free(&box);
		return TRUE;
	}

	/* start export/import */
	dsync_brain_sync_mailbox_init(brain, box, &local_dsync_box, FALSE);
	if (dsync_brain_sync_mailbox_open(brain, dsync_box) < 0)
		return TRUE;

	brain->state = DSYNC_STATE_SYNC_MAILS;
	return TRUE;
}
示例#2
0
bool dsync_brain_slave_recv_mailbox(struct dsync_brain *brain)
{
	const struct dsync_mailbox *dsync_box;
	struct dsync_mailbox local_dsync_box;
	struct mailbox *box;
	int ret;

	i_assert(!brain->master_brain);
	i_assert(brain->box == NULL);

	if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0)
		return FALSE;
	if (ret < 0) {
		brain->state = DSYNC_STATE_DONE;
		return TRUE;
	}

	if (dsync_brain_mailbox_alloc(brain, dsync_box->mailbox_guid, &box) < 0) {
		i_assert(brain->failed);
		return TRUE;
	}
	if (box == NULL) {
		/* mailbox was probably deleted/renamed during sync */
		//FIXME: verify this from log, and if not log an error.
		brain->changes_during_sync = TRUE;
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	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, NULL));
		mailbox_free(&box);
		brain->failed = TRUE;
		return TRUE;
	}

	if ((ret = dsync_box_get(box, &local_dsync_box)) <= 0) {
		mailbox_free(&box);
		if (ret < 0) {
			brain->failed = TRUE;
			return TRUE;
		}
		/* another process just deleted this mailbox? */
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	i_assert(local_dsync_box.uid_validity != 0);
	i_assert(memcmp(dsync_box->mailbox_guid, local_dsync_box.mailbox_guid,
			sizeof(dsync_box->mailbox_guid)) == 0);
	dsync_ibc_send_mailbox(brain->ibc, &local_dsync_box);

	dsync_brain_mailbox_update_pre(brain, box, &local_dsync_box, dsync_box);

	if (brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_CHANGED &&
	    !dsync_boxes_need_sync(&local_dsync_box, dsync_box)) {
		/* no fields appear to have changed, skip this mailbox */
		mailbox_free(&box);
		return TRUE;
	}

	/* start export/import */
	dsync_brain_sync_mailbox_init(brain, box, &local_dsync_box, FALSE);
	if (dsync_brain_sync_mailbox_open(brain, dsync_box) < 0)
		return TRUE;

	brain->state = DSYNC_STATE_SYNC_MAILS;
	return TRUE;
}
int dsync_brain_mailbox_tree_sync_change(struct dsync_brain *brain,
			const struct dsync_mailbox_tree_sync_change *change,
			enum mail_error *error_r)
{
	struct mailbox *box = NULL, *destbox;
	const char *errstr, *func_name = NULL, *storage_name;
	enum mail_error error;
	int ret = -1;

	if (brain->backup_send) {
		i_assert(brain->no_backup_overwrite);
		return 0;
	}

	switch (change->type) {
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_BOX:
		/* make sure we're deleting the correct mailbox */
		ret = dsync_brain_mailbox_alloc(brain, change->mailbox_guid,
						&box, &errstr, error_r);
		if (ret < 0) {
			i_error("Mailbox sync: Couldn't allocate mailbox GUID %s: %s",
				guid_128_to_string(change->mailbox_guid), errstr);
			return -1;
		}
		if (ret == 0) {
			if (brain->debug) {
				i_debug("brain %c: Change during sync: "
					"Mailbox GUID %s deletion conflict: %s",
					brain->master_brain ? 'M' : 'S',
					guid_128_to_string(change->mailbox_guid), errstr);
			}
			brain->changes_during_sync = TRUE;
			return 0;
		}
		break;
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_DIR:
		storage_name = mailbox_list_get_storage_name(change->ns->list,
							     change->full_name);
		if (mailbox_list_delete_dir(change->ns->list, storage_name) == 0)
			return 0;

		errstr = mailbox_list_get_last_error(change->ns->list, &error);
		if (error == MAIL_ERROR_NOTFOUND ||
		    error == MAIL_ERROR_EXISTS) {
			if (brain->debug) {
				i_debug("brain %c: Change during sync: "
					"Mailbox %s mailbox_list_delete_dir conflict: %s",
					brain->master_brain ? 'M' : 'S',
					change->full_name, errstr);
			}
			brain->changes_during_sync = TRUE;
			return 0;
		} else {
			i_error("Mailbox sync: mailbox_list_delete_dir failed: %s",
				errstr);
			*error_r = error;
			return -1;
		}
	default:
		box = mailbox_alloc(change->ns->list, change->full_name, 0);
		break;
	}
	switch (change->type) {
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_CREATE_BOX:
		ret = sync_create_box(brain, box, change->mailbox_guid,
				      change->uid_validity, error_r);
		mailbox_free(&box);
		return ret;
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_CREATE_DIR:
		ret = mailbox_create(box, NULL, TRUE);
		if (ret < 0 &&
		    mailbox_get_last_mail_error(box) == MAIL_ERROR_EXISTS) {
			/* it doesn't matter if somebody else created this
			   directory or we automatically did while creating its
			   child mailbox. it's there now anyway and we don't
			   gain anything by treating this failure any
			   differently from success. */
			ret = 0;
		}
		func_name = "mailbox_create";
		break;
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_BOX:
		ret = mailbox_delete(box);
		func_name = "mailbox_delete";
		break;
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_DIR:
		i_unreached();
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_RENAME:
		destbox = mailbox_alloc(change->ns->list,
					change->rename_dest_name, 0);
		ret = mailbox_rename(box, destbox);
		func_name = "mailbox_rename";
		mailbox_free(&destbox);
		break;
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_SUBSCRIBE:
		ret = mailbox_set_subscribed(box, TRUE);
		func_name = "mailbox_set_subscribed";
		break;
	case DSYNC_MAILBOX_TREE_SYNC_TYPE_UNSUBSCRIBE:
		ret = mailbox_set_subscribed(box, FALSE);
		func_name = "mailbox_set_subscribed";
		break;
	}
	if (ret < 0) {
		errstr = mailbox_get_last_error(box, &error);
		if (error == MAIL_ERROR_EXISTS ||
		    error == MAIL_ERROR_NOTFOUND) {
			/* mailbox was already created or was already deleted.
			   let the next sync figure out what to do */
			if (brain->debug) {
				i_debug("brain %c: Change during sync: "
					"Mailbox %s %s conflict: %s",
					brain->master_brain ? 'M' : 'S',
					mailbox_get_vname(box),
					func_name, errstr);
			}
			brain->changes_during_sync = TRUE;
			ret = 0;
		} else {
			i_error("Mailbox %s sync: %s failed: %s",
				mailbox_get_vname(box), func_name, errstr);
			*error_r = error;
		}
	}
	mailbox_free(&box);
	return ret;
}