#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