summaryrefslogtreecommitdiffstats
path: root/src/plugins/virtual/virtual-storage.h
blob: 1f34e3930ced250ae2007c40783806755f65ee05 (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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#ifndef VIRTUAL_STORAGE_H
#define VIRTUAL_STORAGE_H

#include "seq-range-array.h"
#include "index-storage.h"

#define VIRTUAL_STORAGE_NAME "virtual"
#define VIRTUAL_SUBSCRIPTION_FILE_NAME ".virtual-subscriptions"
#define VIRTUAL_CONFIG_FNAME "dovecot-virtual"

#define VIRTUAL_CONTEXT(obj) \
	MODULE_CONTEXT(obj, virtual_storage_module)
#define VIRTUAL_CONTEXT_REQUIRE(obj) \
	MODULE_CONTEXT_REQUIRE(obj, virtual_storage_module)

#define VIRTUAL_MAIL_INDEX_EXT2_HEADER_VERSION 1

struct virtual_save_context;

struct virtual_mail_index_header {
	/* Increased by one each time the header is modified */
	uint32_t change_counter;
	/* Number of mailbox records following this header. Mailbox names
	   follow the mailbox records - they have neither NUL terminator nor
	   padding. */
	uint32_t mailbox_count;
	/* Highest used mailbox ID. IDs are never reused. */
	uint32_t highest_mailbox_id;
	/* CRC32 of all the search parameters. If it changes, the mailbox is
	   rebuilt. */
	uint32_t search_args_crc32;
};

struct virtual_mail_index_mailbox_record {
	/* Unique mailbox ID used as mailbox_id in records. */
	uint32_t id;
	/* Length of this mailbox's name. */
	uint32_t name_len;
	/* Synced UID validity value */
	uint32_t uid_validity;
	/* Next unseen UID */
	uint32_t next_uid;
	/* Synced highest modseq value */
	uint64_t highest_modseq;
};

struct virtual_mail_index_ext2_header {
	/* Version compatibility number:
	   VIRTUAL_MAIL_INDEX_EXT2_HEADER_VERSION */
	uint8_t version;
	/* Set to sizeof(struct virtual_mail_index_mailbox_ext2_record) when
	   writing. */
	uint8_t ext_record_size;
	/* Set to sizeof(struct virtual_mail_index_ext2_header) when writing. */
	uint16_t hdr_size;
	/* Must be the same as virtual_mail_index_header.change_counter.
	   If not, it means the header was modified by an older Dovecot version
	   and this extension header should be ignored/rewritten. */
	uint32_t change_counter;
};

struct virtual_mail_index_mailbox_ext2_record {
	/* Synced GUID value */
	uint8_t guid[16];
};

struct virtual_mail_index_record {
	uint32_t mailbox_id;
	uint32_t real_uid;
};

struct virtual_storage {
	struct mail_storage storage;

	/* List of mailboxes while a virtual mailbox is being opened.
	   Used to track loops. */
	ARRAY_TYPE(const_string) open_stack;

	unsigned int max_open_mailboxes;
};

struct virtual_backend_uidmap {
	uint32_t real_uid;
	/* can be 0 temporarily while syncing before the UID is assigned */
	uint32_t virtual_uid;
};

struct virtual_backend_box {
	union mailbox_module_context module_ctx;
	struct virtual_mailbox *virtual_mbox;

	/* linked list for virtual_mailbox->open_backend_boxes_{head,tail} */
	struct virtual_backend_box *prev_open, *next_open;

	/* Initially zero, updated by syncing */
	uint32_t mailbox_id;
	const char *name;

	unsigned int sync_mailbox_idx1;
	uint32_t sync_uid_validity;
	uint32_t sync_next_uid;
	uint64_t sync_highest_modseq;
	guid_128_t sync_guid;
	/* this value is either 0 or same as sync_highest_modseq. it's kept 0
	   when there are pending removes that have yet to be expunged */
	uint64_t ondisk_highest_modseq;

	struct mail_search_args *search_args;
	struct mail_search_result *search_result;

	struct mailbox *box;
	/* Messages currently included in the virtual mailbox,
	   sorted by real_uid */
	ARRAY(struct virtual_backend_uidmap) uids;

	/* temporary mail used while syncing */
	struct mail *sync_mail;
	/* pending removed UIDs */
	ARRAY_TYPE(seq_range) sync_pending_removes;
	/* another process expunged these UIDs. they need to be removed on
	   next sync. */
	ARRAY_TYPE(seq_range) sync_outside_expunges;

	/* name contains a wildcard, this is a glob for it */
	struct imap_match_glob *glob;
	struct mail_namespace *ns;
	/* mailbox metadata matching */
	const char *metadata_entry, *metadata_value;

	/* notify context */
	struct mailbox_list_notify *notify;

	bool open_tracked:1;
	bool open_failed:1;
	bool sync_seen:1;
	bool wildcard:1;
	bool clear_recent:1;
	bool negative_match:1;
	bool uids_nonsorted:1;
	bool search_args_initialized:1;
	bool deleted:1;
	bool notify_changes_started:1; /* if the box was opened for notify_changes */
	bool first_sync:1; /* if this is the first sync after bbox was (re-)created */
};
ARRAY_DEFINE_TYPE(virtual_backend_box, struct virtual_backend_box *);

struct virtual_mailbox {
	struct mailbox box;
	struct virtual_storage *storage;

	uint32_t virtual_ext_id;
	uint32_t virtual_ext2_id;
	uint32_t virtual_guid_ext_id;

	uint32_t prev_uid_validity;
	uint32_t prev_change_counter;
	uint32_t highest_mailbox_id;
	uint32_t search_args_crc32;
	guid_128_t guid;

	struct virtual_backend_box *lookup_prev_bbox;
	uint32_t sync_virtual_next_uid;

	/* Mailboxes this virtual mailbox consists of, sorted by mailbox_id */
	ARRAY_TYPE(virtual_backend_box) backend_boxes;
	/* backend mailbox where to save messages when saving to this mailbox */
	struct virtual_backend_box *save_bbox;

	/* linked list of open backend mailboxes. head will contain the oldest
	   accessed mailbox, tail will contain the newest. */
	struct virtual_backend_box *open_backend_boxes_head;
	struct virtual_backend_box *open_backend_boxes_tail;
	/* number of backend mailboxes that are open currently. */
	unsigned int backends_open_count;

	ARRAY_TYPE(mailbox_virtual_patterns) list_include_patterns;
	ARRAY_TYPE(mailbox_virtual_patterns) list_exclude_patterns;

	bool uids_mapped:1;
	bool sync_initialized:1;
	bool inconsistent:1;
	bool have_guid_flags_set:1;
	bool have_guids:1;
	bool have_save_guids:1;
	bool ext_header_rewrite:1;
};

extern MODULE_CONTEXT_DEFINE(virtual_storage_module,
			     &mail_storage_module_register);

extern struct mail_storage virtual_storage;
extern struct mail_vfuncs virtual_mail_vfuncs;

int virtual_config_read(struct virtual_mailbox *mbox);
void virtual_config_free(struct virtual_mailbox *mbox);

int virtual_mailbox_ext_header_read(struct virtual_mailbox *mbox,
				    struct mail_index_view *view,
				    bool *broken_r);

struct virtual_backend_box *
virtual_backend_box_lookup_name(struct virtual_mailbox *mbox, const char *name);
struct virtual_backend_box *
virtual_backend_box_lookup(struct virtual_mailbox *mbox, uint32_t mailbox_id);

int virtual_backend_box_open(struct virtual_mailbox *mbox,
			     struct virtual_backend_box *bbox);
void virtual_backend_box_close(struct virtual_mailbox *mbox,
			       struct virtual_backend_box *bbox);
void virtual_backend_box_accessed(struct virtual_mailbox *mbox,
				  struct virtual_backend_box *bbox);
void virtual_backend_box_sync_mail_unset(struct virtual_backend_box *bbox);

struct mail_search_context *
virtual_search_init(struct mailbox_transaction_context *t,
		    struct mail_search_args *args,
		    const enum mail_sort_type *sort_program,
		    enum mail_fetch_field wanted_fields,
		    struct mailbox_header_lookup_ctx *wanted_headers);
int virtual_search_deinit(struct mail_search_context *ctx);
bool virtual_search_next_nonblock(struct mail_search_context *ctx,
				  struct mail **mail_r, bool *tryagain_r);
bool virtual_search_next_update_seq(struct mail_search_context *ctx);

struct mail *
virtual_mail_alloc(struct mailbox_transaction_context *t,
		   enum mail_fetch_field wanted_fields,
		   struct mailbox_header_lookup_ctx *wanted_headers);
struct mail *
virtual_mail_set_backend_mail(struct mail *mail,
			      struct virtual_backend_box *bbox);
void virtual_mail_set_unattached_backend_mail(struct mail *mail,
					      struct mail *backend_mail);

struct mailbox_sync_context *
virtual_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);

struct mail_save_context *
virtual_save_alloc(struct mailbox_transaction_context *t);
int virtual_save_begin(struct mail_save_context *ctx, struct istream *input);
int virtual_save_continue(struct mail_save_context *ctx);
int virtual_save_finish(struct mail_save_context *ctx);
void virtual_save_cancel(struct mail_save_context *ctx);
void virtual_save_free(struct mail_save_context *ctx);

void virtual_box_copy_error(struct mailbox *dest, struct mailbox *src);

void virtual_backend_mailbox_allocated(struct mailbox *box);
void virtual_backend_mailbox_opened(struct mailbox *box);

#endif