diff options
Diffstat (limited to 'src/doveadm/dsync/dsync-mailbox-tree.h')
-rw-r--r-- | src/doveadm/dsync/dsync-mailbox-tree.h | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/doveadm/dsync/dsync-mailbox-tree.h b/src/doveadm/dsync/dsync-mailbox-tree.h new file mode 100644 index 0000000..6969813 --- /dev/null +++ b/src/doveadm/dsync/dsync-mailbox-tree.h @@ -0,0 +1,205 @@ +#ifndef DSYNC_MAILBOX_TREE_H +#define DSYNC_MAILBOX_TREE_H + +#include "guid.h" +#include "mail-error.h" + +struct mail_namespace; +struct dsync_brain; + +enum dsync_mailbox_trees_sync_type { + /* two-way sync for both mailboxes */ + DSYNC_MAILBOX_TREES_SYNC_TYPE_TWOWAY, + /* make remote tree look exactly like the local tree */ + DSYNC_MAILBOX_TREES_SYNC_TYPE_PRESERVE_LOCAL, + /* make local tree look exactly like the remote tree */ + DSYNC_MAILBOX_TREES_SYNC_TYPE_PRESERVE_REMOTE +}; + +enum dsync_mailbox_trees_sync_flags { + /* Enable debugging */ + DSYNC_MAILBOX_TREES_SYNC_FLAG_DEBUG = 0x01, + /* Show ourself as "master brain" in the debug output */ + DSYNC_MAILBOX_TREES_SYNC_FLAG_MASTER_BRAIN = 0x02, + /* Disable mailbox renaming logic. This is just a kludge that should + be removed once the renaming logic has no more bugs.. */ + DSYNC_MAILBOX_TREES_SYNC_FLAG_NO_RENAMES = 0x04 +}; + +enum dsync_mailbox_node_existence { + /* this is just a filler node for children or for + subscription deletion */ + DSYNC_MAILBOX_NODE_NONEXISTENT = 0, + /* if mailbox GUID is set, the mailbox exists. + otherwise the directory exists. */ + DSYNC_MAILBOX_NODE_EXISTS, + /* if mailbox GUID is set, the mailbox has been deleted. + otherwise the directory has been deleted. */ + DSYNC_MAILBOX_NODE_DELETED +}; + +struct dsync_mailbox_node { + struct dsync_mailbox_node *parent, *next, *first_child; + + /* namespace where this node belongs to */ + struct mail_namespace *ns; + /* this node's name (not including parents) */ + const char *name; + /* mailbox GUID, or full of zeros if this is about a directory name */ + guid_128_t mailbox_guid; + /* mailbox's UIDVALIDITY/UIDNEXT (may be 0 if not assigned yet) */ + uint32_t uid_validity, uid_next; + + /* existence of this mailbox/directory. + doesn't affect subscription state. */ + enum dsync_mailbox_node_existence existence; + /* last time the mailbox/directory was created/renamed, + 0 if not known */ + time_t last_renamed_or_created; + + /* last time the subscription state was changed, 0 if not known */ + time_t last_subscription_change; + /* is this mailbox or directory subscribed? */ + bool subscribed:1; + + /* Internal syncing flags: */ + bool sync_delayed_guid_change:1; + bool sync_temporary_name:1; +}; +ARRAY_DEFINE_TYPE(dsync_mailbox_node, struct dsync_mailbox_node *); + +#define dsync_mailbox_node_guids_equal(node1, node2) \ + (memcmp((node1)->mailbox_guid, (node2)->mailbox_guid, \ + sizeof(guid_128_t)) == 0) + +#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 { + enum dsync_mailbox_delete_type type; + guid_128_t guid; + time_t timestamp; +}; + +enum dsync_mailbox_tree_sync_type { + DSYNC_MAILBOX_TREE_SYNC_TYPE_CREATE_BOX, + DSYNC_MAILBOX_TREE_SYNC_TYPE_CREATE_DIR, + DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_BOX, + DSYNC_MAILBOX_TREE_SYNC_TYPE_DELETE_DIR, + /* Rename given mailbox name and its children */ + DSYNC_MAILBOX_TREE_SYNC_TYPE_RENAME, + DSYNC_MAILBOX_TREE_SYNC_TYPE_SUBSCRIBE, + DSYNC_MAILBOX_TREE_SYNC_TYPE_UNSUBSCRIBE +}; + +struct dsync_mailbox_tree_sync_change { + enum dsync_mailbox_tree_sync_type type; + + /* for all types: */ + struct mail_namespace *ns; + const char *full_name; + + /* for create_box and delete_box: */ + guid_128_t mailbox_guid; + /* for create_box: */ + uint32_t uid_validity; + /* for rename: */ + const char *rename_dest_name; +}; + +struct dsync_mailbox_tree * +dsync_mailbox_tree_init(char sep, char escape_char, char alt_char); +void dsync_mailbox_tree_deinit(struct dsync_mailbox_tree **tree); + +/* Lookup a mailbox node by name. Returns NULL if not known. */ +struct dsync_mailbox_node * +dsync_mailbox_tree_lookup(struct dsync_mailbox_tree *tree, + const char *full_name); +/* Lookup a mailbox node by GUID. Returns NULL if not known. + The mailbox GUID hash must have been build before calling this. */ +struct dsync_mailbox_node * +dsync_mailbox_tree_lookup_guid(struct dsync_mailbox_tree *tree, + const guid_128_t guid); +/* Lookup or create a mailbox node by name. */ +struct dsync_mailbox_node * +dsync_mailbox_tree_get(struct dsync_mailbox_tree *tree, const char *full_name); + +/* Returns full name for the given mailbox node. */ +const char *dsync_mailbox_node_get_full_name(const struct dsync_mailbox_tree *tree, + const struct dsync_mailbox_node *node); +void dsync_mailbox_node_append_full_name(string_t *str, + const struct dsync_mailbox_tree *tree, + const struct dsync_mailbox_node *node); + +/* Copy everything from src to dest, except name and hierarchy pointers */ +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 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, + const guid_128_t box_guid, + const char *const *exclude_mailboxes, + enum mail_error *error_r); + +/* Return all known deleted mailboxes and directories. */ +const struct dsync_mailbox_delete * +dsync_mailbox_tree_get_deletes(struct dsync_mailbox_tree *tree, + unsigned int *count_r); +/* Return mailbox node for a given delete record, or NULL if it doesn't exist. + The delete record is intended to come from another tree, possibly with + a different hierarchy separator. dsync_mailbox_tree_build_guid_hash() must + have been called before this. */ +struct dsync_mailbox_node * +dsync_mailbox_tree_find_delete(struct dsync_mailbox_tree *tree, + const struct dsync_mailbox_delete *del); +/* Build GUID lookup hash, if it's not already built. Returns 0 if ok, -1 if + there are duplicate GUIDs. The nodes with the duplicate GUIDs are + returned. */ +int dsync_mailbox_tree_build_guid_hash(struct dsync_mailbox_tree *tree, + struct dsync_mailbox_node **dup_node1_r, + struct dsync_mailbox_node **dup_node2_r); +/* Manually add a new node to hash. */ +int dsync_mailbox_tree_guid_hash_add(struct dsync_mailbox_tree *tree, + struct dsync_mailbox_node *node, + struct dsync_mailbox_node **old_node_r); +/* Set remote separator used for directory deletions in + dsync_mailbox_tree_find_delete() */ +void dsync_mailbox_tree_set_remote_chars(struct dsync_mailbox_tree *tree, + char remote_sep, + char remote_escape_char); + +/* Iterate through all nodes in a tree (depth-first) */ +struct dsync_mailbox_tree_iter * +dsync_mailbox_tree_iter_init(struct dsync_mailbox_tree *tree); +bool dsync_mailbox_tree_iter_next(struct dsync_mailbox_tree_iter *iter, + const char **full_name_r, + struct dsync_mailbox_node **node_r); +void dsync_mailbox_tree_iter_deinit(struct dsync_mailbox_tree_iter **iter); + +/* Sync local and remote trees so at the end they're exactly the same. + Return changes done to local tree. */ +struct dsync_mailbox_tree_sync_ctx * +dsync_mailbox_trees_sync_init(struct dsync_mailbox_tree *local_tree, + struct dsync_mailbox_tree *remote_tree, + enum dsync_mailbox_trees_sync_type sync_type, + enum dsync_mailbox_trees_sync_flags sync_flags); +const struct dsync_mailbox_tree_sync_change * +dsync_mailbox_trees_sync_next(struct dsync_mailbox_tree_sync_ctx *ctx); +int dsync_mailbox_trees_sync_deinit(struct dsync_mailbox_tree_sync_ctx **ctx); + +const char *dsync_mailbox_node_to_string(const struct dsync_mailbox_node *node); +const char * +dsync_mailbox_delete_type_to_string(enum dsync_mailbox_delete_type type); + +#endif |