/src/dovecot/src/lib-storage/index/dbox-multi/mdbox-mail.c
Line | Count | Source |
1 | | /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "ioloop.h" |
5 | | #include "istream.h" |
6 | | #include "str.h" |
7 | | #include "index-mail.h" |
8 | | #include "dbox-mail.h" |
9 | | #include "mdbox-storage.h" |
10 | | #include "mdbox-sync.h" |
11 | | #include "mdbox-map.h" |
12 | | #include "mdbox-file.h" |
13 | | |
14 | | #include <sys/stat.h> |
15 | | |
16 | | int mdbox_mail_lookup(struct mdbox_mailbox *mbox, struct mail_index_view *view, |
17 | | uint32_t seq, uint32_t *map_uid_r) |
18 | 0 | { |
19 | 0 | const struct mdbox_mail_index_record *dbox_rec; |
20 | 0 | struct mdbox_index_header hdr; |
21 | 0 | const void *data; |
22 | 0 | uint32_t uid, cur_map_uid_validity; |
23 | 0 | bool need_resize; |
24 | |
|
25 | 0 | mail_index_lookup_ext(view, seq, mbox->ext_id, &data, NULL); |
26 | 0 | dbox_rec = data; |
27 | 0 | if (dbox_rec == NULL || dbox_rec->map_uid == 0) { |
28 | 0 | mail_index_lookup_uid(view, seq, &uid); |
29 | 0 | mdbox_set_mailbox_corrupted(&mbox->box, t_strdup_printf( |
30 | 0 | "map uid lost for uid %u", uid)); |
31 | 0 | return -1; |
32 | 0 | } |
33 | | |
34 | 0 | if (mbox->map_uid_validity == 0) { |
35 | 0 | if (mdbox_read_header(mbox, &hdr, &need_resize) < 0) |
36 | 0 | return -1; |
37 | 0 | mbox->map_uid_validity = hdr.map_uid_validity; |
38 | 0 | } |
39 | 0 | if (mdbox_map_open_or_create(mbox->storage->map) < 0) |
40 | 0 | return -1; |
41 | | |
42 | 0 | cur_map_uid_validity = mdbox_map_get_uid_validity(mbox->storage->map); |
43 | 0 | if (cur_map_uid_validity != mbox->map_uid_validity) { |
44 | 0 | mdbox_set_mailbox_corrupted(&mbox->box, t_strdup_printf( |
45 | 0 | "map uidvalidity mismatch (%u vs %u)", |
46 | 0 | mbox->map_uid_validity, cur_map_uid_validity)); |
47 | 0 | return -1; |
48 | 0 | } |
49 | 0 | *map_uid_r = dbox_rec->map_uid; |
50 | 0 | return 0; |
51 | 0 | } |
52 | | |
53 | | static void dbox_mail_set_expunged(struct dbox_mail *mail, uint32_t map_uid) |
54 | 0 | { |
55 | 0 | struct mail *_mail = &mail->imail.mail.mail; |
56 | 0 | struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->box); |
57 | |
|
58 | 0 | mail_index_refresh(_mail->box->index); |
59 | 0 | if (mail_index_is_expunged(_mail->transaction->view, _mail->seq)) { |
60 | 0 | mail_set_expunged(_mail); |
61 | 0 | return; |
62 | 0 | } |
63 | | |
64 | 0 | mdbox_map_set_corrupted(mbox->storage->map, |
65 | 0 | "Unexpectedly lost %s uid=%u map_uid=%u", |
66 | 0 | mailbox_get_vname(_mail->box), |
67 | 0 | _mail->uid, map_uid); |
68 | 0 | } |
69 | | |
70 | | static int dbox_mail_open_init(struct dbox_mail *mail, uint32_t map_uid) |
71 | 0 | { |
72 | 0 | struct mdbox_mailbox *mbox = MDBOX_MAILBOX(mail->imail.mail.mail.box); |
73 | 0 | uint32_t file_id; |
74 | 0 | int ret; |
75 | |
|
76 | 0 | if ((ret = mdbox_map_lookup(mbox->storage->map, map_uid, |
77 | 0 | &file_id, &mail->offset)) <= 0) { |
78 | 0 | if (ret < 0) |
79 | 0 | return -1; |
80 | | |
81 | | /* map_uid doesn't exist anymore. either it |
82 | | got just expunged or the map index is |
83 | | corrupted. */ |
84 | 0 | dbox_mail_set_expunged(mail, map_uid); |
85 | 0 | return -1; |
86 | 0 | } else { |
87 | 0 | mail->open_file = mdbox_file_init(mbox->storage, file_id); |
88 | 0 | } |
89 | 0 | return 0; |
90 | 0 | } |
91 | | |
92 | | int mdbox_mail_file_set(struct dbox_mail *mail) |
93 | 0 | { |
94 | 0 | struct mail *_mail = &mail->imail.mail.mail; |
95 | 0 | struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->box); |
96 | |
|
97 | 0 | if (mail->open_file != NULL) { |
98 | | /* already open */ |
99 | 0 | } else if (!_mail->saving) { |
100 | 0 | uint32_t map_uid; |
101 | 0 | if (mdbox_mail_lookup(mbox, _mail->transaction->view, |
102 | 0 | _mail->seq, &map_uid) < 0) |
103 | 0 | return -1; |
104 | 0 | if (dbox_mail_open_init(mail, map_uid) < 0) |
105 | 0 | return -1; |
106 | 0 | } else { |
107 | | /* mail is being saved in this transaction */ |
108 | 0 | mail->open_file = |
109 | 0 | mdbox_save_file_get_file(_mail->transaction, |
110 | 0 | _mail->seq, |
111 | 0 | &mail->offset); |
112 | 0 | } |
113 | 0 | return 0; |
114 | 0 | } |
115 | | |
116 | | int mdbox_mail_open(struct dbox_mail *mail, uoff_t *offset_r, |
117 | | struct dbox_file **file_r) |
118 | 0 | { |
119 | 0 | struct mail *_mail = &mail->imail.mail.mail; |
120 | 0 | struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->box); |
121 | 0 | uint32_t prev_file_id = 0; |
122 | 0 | bool deleted; |
123 | |
|
124 | 0 | if (!mail_stream_access_start(_mail)) |
125 | 0 | return -1; |
126 | | |
127 | 0 | do { |
128 | 0 | if (mdbox_mail_file_set(mail) < 0) |
129 | 0 | return -1; |
130 | 0 | if (!dbox_file_is_open(mail->open_file)) |
131 | 0 | _mail->transaction->stats.open_lookup_count++; |
132 | 0 | if (dbox_file_open(mail->open_file, &deleted) <= 0) |
133 | 0 | return -1; |
134 | 0 | if (deleted) { |
135 | | /* either it's expunged now or moved to another file. */ |
136 | 0 | struct mdbox_file *mfile = |
137 | 0 | (struct mdbox_file *)mail->open_file; |
138 | |
|
139 | 0 | if (mfile->file_id == prev_file_id) { |
140 | 0 | uint32_t map_uid; |
141 | 0 | if (mdbox_mail_lookup(mbox, _mail->transaction->view, |
142 | 0 | _mail->seq, &map_uid) < 0) |
143 | 0 | return -1; |
144 | 0 | dbox_mail_set_expunged(mail, map_uid); |
145 | 0 | return -1; |
146 | 0 | } |
147 | 0 | prev_file_id = mfile->file_id; |
148 | 0 | if (mdbox_map_refresh(mbox->storage->map) < 0) |
149 | 0 | return -1; |
150 | 0 | dbox_file_unref(&mail->open_file); |
151 | 0 | } |
152 | 0 | } while (mail->open_file == NULL); |
153 | | |
154 | 0 | *file_r = mail->open_file; |
155 | 0 | *offset_r = mail->offset; |
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | | static int mdbox_mail_get_save_date(struct mail *mail, time_t *date_r) |
160 | 0 | { |
161 | 0 | struct mdbox_mailbox *mbox = MDBOX_MAILBOX(mail->transaction->box); |
162 | 0 | const struct mdbox_mail_index_record *dbox_rec; |
163 | 0 | const void *data; |
164 | |
|
165 | 0 | mail_index_lookup_ext(mail->transaction->view, mail->seq, |
166 | 0 | mbox->ext_id, &data, NULL); |
167 | 0 | dbox_rec = data; |
168 | 0 | if (dbox_rec == NULL || dbox_rec->map_uid == 0) { |
169 | | /* lost for some reason, use fallback */ |
170 | 0 | return dbox_mail_get_save_date(mail, date_r); |
171 | 0 | } |
172 | | |
173 | 0 | *date_r = dbox_rec->save_date; |
174 | 0 | return 1; |
175 | 0 | } |
176 | | |
177 | | static int |
178 | | mdbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field, |
179 | | const char **value_r) |
180 | 0 | { |
181 | 0 | struct dbox_mail *mail = DBOX_MAIL(_mail); |
182 | 0 | struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->transaction->box); |
183 | 0 | struct mdbox_map_mail_index_record rec; |
184 | 0 | uint32_t map_uid; |
185 | 0 | uint16_t refcount; |
186 | |
|
187 | 0 | switch (field) { |
188 | 0 | case MAIL_FETCH_REFCOUNT: |
189 | 0 | if (mdbox_mail_lookup(mbox, _mail->transaction->view, |
190 | 0 | _mail->seq, &map_uid) < 0) |
191 | 0 | return -1; |
192 | 0 | if (mdbox_map_lookup_full(mbox->storage->map, map_uid, |
193 | 0 | &rec, &refcount) < 0) |
194 | 0 | return -1; |
195 | 0 | *value_r = p_strdup_printf(mail->imail.mail.data_pool, "%u", |
196 | 0 | refcount); |
197 | 0 | return 0; |
198 | 0 | case MAIL_FETCH_REFCOUNT_ID: |
199 | 0 | if (mdbox_mail_lookup(mbox, _mail->transaction->view, |
200 | 0 | _mail->seq, &map_uid) < 0) |
201 | 0 | return -1; |
202 | 0 | *value_r = p_strdup_printf(mail->imail.mail.data_pool, "%u", |
203 | 0 | map_uid); |
204 | 0 | return 0; |
205 | 0 | case MAIL_FETCH_UIDL_BACKEND: |
206 | 0 | if (!dbox_header_have_flag(&mbox->box, mbox->hdr_ext_id, |
207 | 0 | offsetof(struct mdbox_index_header, flags), |
208 | 0 | DBOX_INDEX_HEADER_FLAG_HAVE_POP3_UIDLS)) { |
209 | 0 | *value_r = ""; |
210 | 0 | return 0; |
211 | 0 | } |
212 | 0 | break; |
213 | 0 | case MAIL_FETCH_POP3_ORDER: |
214 | 0 | if (!dbox_header_have_flag(&mbox->box, mbox->hdr_ext_id, |
215 | 0 | offsetof(struct mdbox_index_header, flags), |
216 | 0 | DBOX_INDEX_HEADER_FLAG_HAVE_POP3_ORDERS)) { |
217 | 0 | *value_r = ""; |
218 | 0 | return 0; |
219 | 0 | } |
220 | 0 | break; |
221 | 0 | default: |
222 | 0 | break; |
223 | 0 | } |
224 | 0 | return dbox_mail_get_special(_mail, field, value_r); |
225 | 0 | } |
226 | | |
227 | | static void |
228 | | mdbox_mail_update_flags(struct mail *mail, enum modify_type modify_type, |
229 | | enum mail_flags flags) |
230 | 0 | { |
231 | 0 | if ((flags & DBOX_INDEX_FLAG_ALT) != 0) { |
232 | 0 | mdbox_purge_alt_flag_change(mail, modify_type != MODIFY_REMOVE); |
233 | 0 | flags &= ENUM_NEGATE(DBOX_INDEX_FLAG_ALT); |
234 | 0 | if (flags == 0 && modify_type != MODIFY_REPLACE) |
235 | 0 | return; |
236 | 0 | } |
237 | | |
238 | 0 | index_mail_update_flags(mail, modify_type, flags); |
239 | 0 | } |
240 | | |
241 | | struct mail_vfuncs mdbox_mail_vfuncs = { |
242 | | dbox_mail_close, |
243 | | index_mail_free, |
244 | | index_mail_set_seq, |
245 | | index_mail_set_uid, |
246 | | index_mail_set_uid_cache_updates, |
247 | | index_mail_prefetch, |
248 | | index_mail_precache, |
249 | | index_mail_add_temp_wanted_fields, |
250 | | |
251 | | index_mail_get_flags, |
252 | | index_mail_get_keywords, |
253 | | index_mail_get_keyword_indexes, |
254 | | index_mail_get_modseq, |
255 | | index_mail_get_pvt_modseq, |
256 | | index_mail_get_parts, |
257 | | index_mail_get_date, |
258 | | dbox_mail_get_received_date, |
259 | | mdbox_mail_get_save_date, |
260 | | dbox_mail_get_virtual_size, |
261 | | dbox_mail_get_physical_size, |
262 | | index_mail_get_first_header, |
263 | | index_mail_get_headers, |
264 | | index_mail_get_header_stream, |
265 | | dbox_mail_get_stream, |
266 | | index_mail_get_binary_stream, |
267 | | mdbox_mail_get_special, |
268 | | index_mail_get_backend_mail, |
269 | | mdbox_mail_update_flags, |
270 | | index_mail_update_keywords, |
271 | | index_mail_update_modseq, |
272 | | index_mail_update_pvt_modseq, |
273 | | NULL, |
274 | | index_mail_expunge, |
275 | | index_mail_set_cache_corrupted, |
276 | | index_mail_opened, |
277 | | }; |