summaryrefslogtreecommitdiffstats
path: root/src/doveadm/dsync/dsync-mailbox-tree.h
blob: 3542ef4a447182d94e1f017722dd71bb57e66587 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#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);

/* Split mailbox name into its hierarchical parts. The mailbox name is
   unescaped if the escape_char is not '\0'. */
const char *const *
dsync_mailbox_name_to_parts(const char *name, char hierarchy_sep,
			    char escape_char);
/* 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,
			    char alt_char,
			    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