i_assert(brain->box == NULL);
if (!dsync_brain_next_mailbox(brain, &box, &dsync_box)) {
- brain->state = DSYNC_STATE_DONE;
+ brain->state = DSYNC_STATE_FINISH;
dsync_ibc_send_end_of_list(brain->ibc, DSYNC_IBC_EOL_MAILBOX);
return;
}
if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0)
return FALSE;
if (ret < 0) {
- brain->state = DSYNC_STATE_DONE;
+ brain->state = DSYNC_STATE_FINISH;
return TRUE;
}
after the mails are synced, another mailbox is synced. */
DSYNC_STATE_SYNC_MAILS,
+ DSYNC_STATE_FINISH,
DSYNC_STATE_DONE
};
"master_send_mailbox",
"slave_recv_mailbox",
"sync_mails",
+ "finish",
"done"
};
return changed;
}
+static bool dsync_brain_finish(struct dsync_brain *brain)
+{
+ const char *error;
+
+ if (!brain->master_brain) {
+ dsync_ibc_send_finish(brain->ibc,
+ brain->failed ? "dsync failed" : NULL);
+ brain->state = DSYNC_STATE_DONE;
+ return TRUE;
+ }
+ if (dsync_ibc_recv_finish(brain->ibc, &error) == DSYNC_IBC_RECV_RET_TRYAGAIN)
+ return FALSE;
+ if (error != NULL) {
+ i_error("Remote dsync failed: %s", error);
+ brain->failed = TRUE;
+ }
+ brain->state = DSYNC_STATE_DONE;
+ return TRUE;
+}
+
static bool dsync_brain_run_real(struct dsync_brain *brain, bool *changed_r)
{
enum dsync_state orig_state = brain->state;
case DSYNC_STATE_SYNC_MAILS:
changed = dsync_brain_sync_mails(brain);
break;
+ case DSYNC_STATE_FINISH:
+ changed = dsync_brain_finish(brain);
+ break;
case DSYNC_STATE_DONE:
changed = TRUE;
ret = FALSE;
ITEM_MAILBOX_ATTRIBUTE,
ITEM_MAIL_CHANGE,
ITEM_MAIL_REQUEST,
- ITEM_MAIL
+ ITEM_MAIL,
+ ITEM_FINISH
};
struct item {
unsigned int count;
char hierarchy_sep;
} mailbox_delete;
+ const char *finish_error;
} u;
};
case ITEM_MAIL_CHANGE:
case ITEM_MAIL_REQUEST:
case ITEM_MAIL:
+ case ITEM_FINISH:
item->pool = dsync_ibc_pipe_get_pool(pipe);
break;
}
return DSYNC_IBC_RECV_RET_OK;
}
+static void
+dsync_ibc_pipe_send_finish(struct dsync_ibc *ibc, const char *error)
+{
+ struct dsync_ibc_pipe *pipe = (struct dsync_ibc_pipe *)ibc;
+ struct item *item;
+
+ item = dsync_ibc_pipe_push_item(pipe->remote, ITEM_FINISH);
+ item->u.finish_error = p_strdup(item->pool, error);
+}
+
+static enum dsync_ibc_recv_ret
+dsync_ibc_pipe_recv_finish(struct dsync_ibc *ibc, const char **error_r)
+{
+ struct dsync_ibc_pipe *pipe = (struct dsync_ibc_pipe *)ibc;
+ struct item *item;
+
+ item = dsync_ibc_pipe_pop_item(pipe, ITEM_FINISH);
+ if (item == NULL)
+ return DSYNC_IBC_RECV_RET_TRYAGAIN;
+
+ *error_r = item->u.finish_error;
+ return DSYNC_IBC_RECV_RET_OK;
+}
+
static void pipe_close_mail_streams(struct dsync_ibc_pipe *pipe)
{
struct item *item;
dsync_ibc_pipe_recv_mail_request,
dsync_ibc_pipe_send_mail,
dsync_ibc_pipe_recv_mail,
+ dsync_ibc_pipe_send_finish,
+ dsync_ibc_pipe_recv_finish,
dsync_ibc_pipe_close_mail_streams,
dsync_ibc_pipe_is_send_queue_full,
dsync_ibc_pipe_has_pending_data
(*recv_mail)(struct dsync_ibc *ibc,
struct dsync_mail **mail_r);
+ void (*send_finish)(struct dsync_ibc *ibc, const char *error);
+ enum dsync_ibc_recv_ret
+ (*recv_finish)(struct dsync_ibc *ibc, const char **error_r);
+
void (*close_mail_streams)(struct dsync_ibc *ibc);
bool (*is_send_queue_full)(struct dsync_ibc *ibc);
bool (*has_pending_data)(struct dsync_ibc *ibc);
#define DSYNC_IBC_STREAM_OUTBUF_THROTTLE_SIZE (1024*128)
#define DSYNC_PROTOCOL_VERSION_MAJOR 3
-#define DSYNC_PROTOCOL_VERSION_MINOR 2
-#define DSYNC_HANDSHAKE_VERSION "VERSION\tdsync\t3\t2\n"
+#define DSYNC_PROTOCOL_VERSION_MINOR 3
+#define DSYNC_HANDSHAKE_VERSION "VERSION\tdsync\t3\t3\n"
#define DSYNC_PROTOCOL_MINOR_HAVE_ATTRIBUTES 1
#define DSYNC_PROTOCOL_MINOR_HAVE_SAVE_GUID 2
+#define DSYNC_PROTOCOL_MINOR_HAVE_FINISH 3
enum item_type {
ITEM_NONE,
ITEM_MAIL_CHANGE,
ITEM_MAIL_REQUEST,
ITEM_MAIL,
+ ITEM_FINISH,
ITEM_MAILBOX_CACHE_FIELD,
.chr = 'M',
.optional_keys = "guid uid pop3_uidl pop3_order received_date saved_date stream"
},
+ { .name = "finish",
+ .chr = 'F',
+ .optional_keys = "error"
+ },
{ .name = "mailbox_cache_field",
.chr = 'c',
.required_keys = "name decision",
return DSYNC_IBC_RECV_RET_OK;
}
+static void
+dsync_ibc_stream_send_finish(struct dsync_ibc *_ibc, const char *error)
+{
+ struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc;
+ struct dsync_serializer_encoder *encoder;
+ string_t *str = t_str_new(128);
+
+ str_append_c(str, items[ITEM_FINISH].chr);
+ encoder = dsync_serializer_encode_begin(ibc->serializers[ITEM_FINISH]);
+ if (error != NULL)
+ dsync_serializer_encode_add(encoder, "error", error);
+ dsync_serializer_encode_finish(&encoder, str);
+ dsync_ibc_stream_send_string(ibc, str);
+}
+
+static enum dsync_ibc_recv_ret
+dsync_ibc_stream_recv_finish(struct dsync_ibc *_ibc, const char **error_r)
+{
+ struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc;
+ struct dsync_deserializer_decoder *decoder;
+ const char *value;
+ enum dsync_ibc_recv_ret ret;
+
+ *error_r = NULL;
+ p_clear(ibc->ret_pool);
+
+ if (ibc->minor_version < DSYNC_PROTOCOL_MINOR_HAVE_FINISH)
+ return DSYNC_IBC_RECV_RET_OK;
+
+ ret = dsync_ibc_stream_input_next(ibc, ITEM_FINISH, &decoder);
+ if (ret != DSYNC_IBC_RECV_RET_OK)
+ return ret;
+
+ if (dsync_deserializer_decode_try(decoder, "error", &value))
+ *error_r = p_strdup(ibc->ret_pool, value);
+ return DSYNC_IBC_RECV_RET_OK;
+}
+
static void dsync_ibc_stream_close_mail_streams(struct dsync_ibc *_ibc)
{
struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc;
dsync_ibc_stream_recv_mail_request,
dsync_ibc_stream_send_mail,
dsync_ibc_stream_recv_mail,
+ dsync_ibc_stream_send_finish,
+ dsync_ibc_stream_recv_finish,
dsync_ibc_stream_close_mail_streams,
dsync_ibc_stream_is_send_queue_full,
dsync_ibc_stream_has_pending_data
return ibc->v.recv_mail(ibc, mail_r);
}
+void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error)
+{
+ ibc->v.send_finish(ibc, error);
+}
+
+enum dsync_ibc_recv_ret
+dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r)
+{
+ return ibc->v.recv_finish(ibc, error_r);
+}
+
void dsync_ibc_close_mail_streams(struct dsync_ibc *ibc)
{
ibc->v.close_mail_streams(ibc);
enum dsync_ibc_recv_ret
dsync_ibc_recv_mail(struct dsync_ibc *ibc, struct dsync_mail **mail_r);
+void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error);
+enum dsync_ibc_recv_ret
+dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r);
+
/* Close any mail input streams that are kept open. This needs to be called
before the mail is attempted to be freed (usually on error conditions). */
void dsync_ibc_close_mail_streams(struct dsync_ibc *ibc);