Similar to -m <mailbox name>.
#include <ctype.h>
#include <sys/wait.h>
-#define DSYNC_COMMON_GETOPT_ARGS "+dEfl:m:n:Nr:Rs:"
+#define DSYNC_COMMON_GETOPT_ARGS "+dEfg:l:m:n:Nr:Rs:"
#define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30
enum dsync_run_type {
struct doveadm_mail_cmd_context ctx;
enum dsync_brain_sync_type sync_type;
const char *mailbox, *namespace_prefix;
+ guid_128_t mailbox_guid;
const char *state_input, *rawlog_path;
const char *remote_name;
unsigned int backup:1;
unsigned int reverse_backup:1;
unsigned int remote_user_prefix:1;
+ unsigned int no_mail_sync:1;
};
static bool legacy_dsync = FALSE;
else if (ctx->backup)
brain_flags |= DSYNC_BRAIN_FLAG_BACKUP_SEND;
+ if (ctx->no_mail_sync)
+ brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC;
if (doveadm_debug)
brain_flags |= DSYNC_BRAIN_FLAG_DEBUG;
- if (ctx->mailbox != NULL && *ctx->mailbox == '\0') {
- brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC;
- ctx->mailbox = NULL;
- }
brain = dsync_brain_master_init(user, ibc, sync_ns, ctx->mailbox,
+ ctx->mailbox_guid,
ctx->sync_type, brain_flags,
ctx->lock_timeout,
ctx->state_input == NULL ? "" :
case 'f':
ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_FULL;
break;
+ case 'g':
+ if (optarg[0] == '\0')
+ ctx->no_mail_sync = TRUE;
+ else if (guid_128_from_string(optarg, ctx->mailbox_guid) < 0 ||
+ guid_128_is_empty(ctx->mailbox_guid))
+ i_error("Invalid -g parameter: %s", optarg);
+ break;
case 'l':
ctx->lock = TRUE;
if (str_to_uint(optarg, &ctx->lock_timeout) < 0)
i_error("Invalid -l parameter: %s", optarg);
break;
case 'm':
- ctx->mailbox = optarg;
+ if (optarg[0] == '\0')
+ ctx->no_mail_sync = TRUE;
+ else
+ ctx->mailbox = optarg;
break;
case 'n':
ctx->namespace_prefix = optarg;
/* fill the local mailbox tree */
if (brain->sync_ns != NULL) {
if (dsync_mailbox_tree_fill(brain->local_mailbox_tree,
- brain->sync_ns, brain->sync_box) < 0)
+ brain->sync_ns, brain->sync_box,
+ brain->sync_box_guid) < 0)
brain->failed = TRUE;
} else {
for (ns = brain->user->namespaces; ns != NULL; ns = ns->next) {
if (!dsync_brain_want_namespace(brain, ns))
continue;
if (dsync_mailbox_tree_fill(brain->local_mailbox_tree,
- ns, brain->sync_box) < 0)
+ ns, brain->sync_box,
+ brain->sync_box_guid) < 0)
brain->failed = TRUE;
}
}
struct mail_user *user;
struct dsync_ibc *ibc;
struct mail_namespace *sync_ns;
- char *sync_box;
+ const char *sync_box;
+ guid_128_t sync_box_guid;
enum dsync_brain_sync_type sync_type;
unsigned int lock_timeout;
struct dsync_brain *
dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc,
struct mail_namespace *sync_ns, const char *sync_box,
+ const guid_128_t sync_box_guid,
enum dsync_brain_sync_type sync_type,
enum dsync_brain_flags flags, unsigned int lock_timeout,
const char *state)
if (sync_ns != NULL)
brain->sync_ns = sync_ns;
brain->sync_box = p_strdup(brain->pool, sync_box);
+ memcpy(brain->sync_box_guid, sync_box_guid, sizeof(brain->sync_box_guid));
brain->lock_timeout = lock_timeout;
brain->master_brain = TRUE;
dsync_brain_set_flags(brain, flags);
ibc_set.hostname = my_hostdomain();
ibc_set.sync_ns_prefix = sync_ns == NULL ? NULL : sync_ns->prefix;
ibc_set.sync_box = sync_box;
+ memcpy(ibc_set.sync_box_guid, sync_box_guid,
+ sizeof(ibc_set.sync_box_guid));
ibc_set.sync_type = sync_type;
ibc_set.lock_timeout = lock_timeout;
/* reverse the backup direction for the slave */
ibc_set->sync_ns_prefix);
}
brain->sync_box = p_strdup(brain->pool, ibc_set->sync_box);
+ memcpy(brain->sync_box_guid, ibc_set->sync_box_guid,
+ sizeof(brain->sync_box_guid));
i_assert(brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_UNKNOWN);
brain->sync_type = ibc_set->sync_type;
dsync_brain_set_flags(brain, ibc_set->brain_flags);
#ifndef DSYNC_BRAIN_H
#define DSYNC_BRAIN_H
+#include "guid.h"
+
struct mail_namespace;
struct mail_user;
struct dsync_ibc;
struct dsync_brain *
dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc,
struct mail_namespace *sync_ns, const char *sync_box,
+ const guid_128_t sync_box_guid,
enum dsync_brain_sync_type sync_type,
enum dsync_brain_flags flags, unsigned int lock_timeout,
const char *state);
item->u.set = *set;
item->u.set.sync_ns_prefix = p_strdup(item->pool, set->sync_ns_prefix);
item->u.set.sync_box = p_strdup(item->pool, set->sync_box);
+ memcpy(item->u.set.sync_box_guid, set->sync_box_guid,
+ sizeof(item->u.set.sync_box_guid));
}
static enum dsync_ibc_recv_ret
{ .name = "handshake",
.chr = 'H',
.required_keys = "hostname",
- .optional_keys = "sync_ns_prefix sync_box sync_type debug sync_visible_namespaces "
+ .optional_keys = "sync_ns_prefix sync_box sync_box_guid sync_type "
+ "debug sync_visible_namespaces "
"send_mail_requests backup_send backup_recv lock_timeout"
},
{ .name = "mailbox_state",
}
if (set->sync_box != NULL)
dsync_serializer_encode_add(encoder, "sync_box", set->sync_box);
+ if (!guid_128_is_empty(set->sync_box_guid)) {
+ dsync_serializer_encode_add(encoder, "sync_box_guid",
+ guid_128_to_string(set->sync_box_guid));
+ }
sync_type[0] = sync_type[1] = '\0';
switch (set->sync_type) {
set->sync_ns_prefix = p_strdup(pool, value);
if (dsync_deserializer_decode_try(decoder, "sync_box", &value))
set->sync_box = p_strdup(pool, value);
+ if (dsync_deserializer_decode_try(decoder, "sync_box_guid", &value) &&
+ guid_128_from_string(value, set->sync_box_guid) < 0) {
+ dsync_ibc_input_error(ibc, decoder,
+ "Invalid sync_box_guid: %s", value);
+ return DSYNC_IBC_RECV_RET_TRYAGAIN;
+ }
if (dsync_deserializer_decode_try(decoder, "sync_type", &value)) {
switch (value[0]) {
case 'f':
const char *sync_ns_prefix;
/* if non-NULL, sync only this mailbox name */
const char *sync_box;
+ /* if non-empty, sync only this mailbox GUID */
+ guid_128_t sync_box_guid;
enum dsync_brain_sync_type sync_type;
enum dsync_brain_flags brain_flags;
return 0;
}
+static int
+dsync_mailbox_tree_add_exists_node(struct dsync_mailbox_tree *tree,
+ const struct mailbox_info *info,
+ struct dsync_mailbox_node **node_r)
+{
+ if (dsync_mailbox_tree_add_node(tree, info, node_r) < 0)
+ return -1;
+ (*node_r)->existence = DSYNC_MAILBOX_NODE_EXISTS;
+ return 0;
+}
+
static int
dsync_mailbox_tree_get_selectable(struct mailbox *box,
struct mailbox_metadata *metadata_r,
}
static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree,
- const struct mailbox_info *info)
+ const struct mailbox_info *info,
+ const guid_128_t box_guid)
{
struct dsync_mailbox_node *node;
struct mailbox *box;
struct mailbox_status status;
const char *errstr;
enum mail_error error;
+ int ret = 0;
if ((info->flags & MAILBOX_NONEXISTENT) != 0)
return 0;
-
- if (dsync_mailbox_tree_add_node(tree, info, &node) < 0)
- return -1;
- node->existence = DSYNC_MAILBOX_NODE_EXISTS;
-
- if ((info->flags & MAILBOX_NOSELECT) != 0)
- return 0;
+ if ((info->flags & MAILBOX_NOSELECT) != 0) {
+ return !guid_128_is_empty(box_guid) ? 0 :
+ dsync_mailbox_tree_add_exists_node(tree, info, &node);
+ }
/* get GUID and UIDVALIDITY for selectable mailbox */
box = mailbox_alloc(info->ns->list, info->vname, 0);
default:
i_error("Failed to access mailbox %s: %s",
info->vname, errstr);
- mailbox_free(&box);
- return -1;
+ ret = -1;
}
- } else {
- memcpy(node->mailbox_guid, metadata.guid,
- sizeof(node->mailbox_guid));
- node->uid_validity = status.uidvalidity;
- node->uid_next = status.uidnext;
+ mailbox_free(&box);
+ return ret;
}
mailbox_free(&box);
+
+ if (!guid_128_is_empty(box_guid) &&
+ !guid_128_equals(box_guid, metadata.guid)) {
+ /* unwanted mailbox */
+ return 0;
+ }
+ if (dsync_mailbox_tree_add_exists_node(tree, info, &node) < 0)
+ return -1;
+ memcpy(node->mailbox_guid, metadata.guid,
+ sizeof(node->mailbox_guid));
+ node->uid_validity = status.uidvalidity;
+ node->uid_next = status.uidnext;
return 0;
}
}
int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
- struct mail_namespace *ns, const char *box_name)
+ struct mail_namespace *ns, const char *box_name,
+ const guid_128_t box_guid)
{
const enum mailbox_list_iter_flags list_flags =
/* FIXME: we'll skip symlinks, because we can't handle them
/* first add all of the existing mailboxes */
iter = mailbox_list_iter_init(ns->list, list_pattern, list_flags);
while ((info = mailbox_list_iter_next(iter)) != NULL) {
- if (dsync_mailbox_tree_add(tree, info) < 0)
+ if (dsync_mailbox_tree_add(tree, info, box_guid) < 0)
ret = -1;
}
if (mailbox_list_iter_deinit(&iter) < 0) {
void dsync_mailbox_node_copy_data(struct dsync_mailbox_node *dest,
const struct dsync_mailbox_node *src);
-/* Add nodes to tree from the given namespace. If box_name is non-NULL,
- add only that mailbox to the tree. */
+/* Add nodes to tree from the given namespace. If box_name or box_guid is
+ non-NULL, add only that mailbox to the tree. */
int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree,
- struct mail_namespace *ns, const char *box_name);
+ struct mail_namespace *ns, const char *box_name,
+ const guid_128_t box_guid);
/* Return all known deleted mailboxes and directories. */
const struct dsync_mailbox_delete *