1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "buffer.h"
6 #include "ioloop.h"
7 #include "istream.h"
8 #include "hex-binary.h"
9 #include "str.h"
10 #include "mailbox-recent-flags.h"
11 #include "message-date.h"
12 #include "message-part-data.h"
13 #include "message-part-serialize.h"
14 #include "message-parser.h"
15 #include "message-snippet.h"
16 #include "imap-bodystructure.h"
17 #include "imap-envelope.h"
18 #include "mail-cache.h"
19 #include "mail-index-modseq.h"
20 #include "index-storage.h"
21 #include "istream-mail.h"
22 #include "index-mail.h"
23
24 #include <fcntl.h>
25
26 #define BODY_SNIPPET_ALGO_V1 "1"
27 #define BODY_SNIPPET_MAX_CHARS 200
28
29 struct mail_cache_field global_cache_fields[MAIL_INDEX_CACHE_FIELD_COUNT] = {
30 { .name = "flags",
31 .type = MAIL_CACHE_FIELD_BITMASK,
32 .field_size = sizeof(uint32_t) },
33 { .name = "date.sent",
34 .type = MAIL_CACHE_FIELD_FIXED_SIZE,
35 .field_size = sizeof(struct mail_sent_date) },
36 { .name = "date.received",
37 .type = MAIL_CACHE_FIELD_FIXED_SIZE,
38 .field_size = sizeof(uint32_t) },
39 { .name = "date.save",
40 .type = MAIL_CACHE_FIELD_FIXED_SIZE,
41 .field_size = sizeof(uint32_t) },
42 { .name = "size.virtual",
43 .type = MAIL_CACHE_FIELD_FIXED_SIZE,
44 .field_size = sizeof(uoff_t) },
45 { .name = "size.physical",
46 .type = MAIL_CACHE_FIELD_FIXED_SIZE,
47 .field_size = sizeof(uoff_t) },
48 { .name = "imap.body",
49 .type = MAIL_CACHE_FIELD_STRING },
50 { .name = "imap.bodystructure",
51 .type = MAIL_CACHE_FIELD_STRING },
52 { .name = "imap.envelope",
53 .type = MAIL_CACHE_FIELD_STRING },
54 { .name = "pop3.uidl",
55 .type = MAIL_CACHE_FIELD_STRING },
56 { .name = "pop3.order",
57 .type = MAIL_CACHE_FIELD_FIXED_SIZE,
58 .field_size = sizeof(uint32_t) },
59 { .name = "guid",
60 .type = MAIL_CACHE_FIELD_STRING },
61 { .name = "mime.parts",
62 .type = MAIL_CACHE_FIELD_VARIABLE_SIZE },
63 { .name = "binary.parts",
64 .type = MAIL_CACHE_FIELD_VARIABLE_SIZE },
65 { .name = "body.snippet",
66 .type = MAIL_CACHE_FIELD_VARIABLE_SIZE }
67 /* FIXME: for now need to update get_metadata_precache_fields() in
68 index-status.c when adding more fields. those fields should probably
69 just be moved here to the same struct. */
70 };
71
72 static void index_mail_init_data(struct index_mail *mail);
73 static int index_mail_parse_body(struct index_mail *mail,
74 enum index_cache_field field);
75 static int index_mail_write_body_snippet(struct index_mail *mail);
76
index_mail_cache_lookup_field(struct index_mail * mail,buffer_t * buf,unsigned int field_idx)77 int index_mail_cache_lookup_field(struct index_mail *mail, buffer_t *buf,
78 unsigned int field_idx)
79 {
80 struct mail *_mail = &mail->mail.mail;
81 int ret;
82
83 ret = mail_cache_lookup_field(mail->mail.mail.transaction->cache_view,
84 buf, mail->data.seq, field_idx);
85 if (ret > 0)
86 mail->mail.mail.transaction->stats.cache_hit_count++;
87
88 /* If the request was lazy mark the field as cache wanted. */
89 if (_mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE_START_CACHING &&
90 mail_cache_field_get_decision(_mail->box->cache, field_idx) ==
91 MAIL_CACHE_DECISION_NO) {
92 mail_cache_decision_add(_mail->transaction->cache_view,
93 _mail->seq, field_idx);
94 }
95
96 return ret;
97 }
98
index_mail_try_set_attachment_keywords(struct index_mail * mail)99 static void index_mail_try_set_attachment_keywords(struct index_mail *mail)
100 {
101 enum mail_lookup_abort orig_lookup_abort = mail->mail.mail.lookup_abort;
102 mail->mail.mail.lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
103 (void)mail_set_attachment_keywords(&mail->mail.mail);
104 mail->mail.mail.lookup_abort = orig_lookup_abort;
105 }
106
107 static bool
index_mail_want_attachment_keywords_on_fetch(struct index_mail * mail)108 index_mail_want_attachment_keywords_on_fetch(struct index_mail *mail)
109 {
110 const struct mail_storage_settings *mail_set =
111 mailbox_get_settings(mail->mail.mail.box);
112
113 return mail_set->parsed_mail_attachment_detection_add_flags &&
114 !mail_set->parsed_mail_attachment_detection_no_flags_on_fetch &&
115 !mail_has_attachment_keywords(&mail->mail.mail);
116 }
117
get_serialized_parts(struct index_mail * mail,buffer_t ** part_buf_r)118 static int get_serialized_parts(struct index_mail *mail, buffer_t **part_buf_r)
119 {
120 const unsigned int field_idx =
121 mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx;
122
123 *part_buf_r = t_buffer_create(128);
124 return index_mail_cache_lookup_field(mail, *part_buf_r, field_idx);
125 }
126
get_unserialized_parts(struct index_mail * mail)127 static struct message_part *get_unserialized_parts(struct index_mail *mail)
128 {
129 struct message_part *parts;
130 buffer_t *part_buf;
131 const char *error;
132
133 if (get_serialized_parts(mail, &part_buf) <= 0)
134 return NULL;
135
136 parts = message_part_deserialize(mail->mail.data_pool, part_buf->data,
137 part_buf->used, &error);
138 if (parts == NULL) {
139 mail_set_mail_cache_corrupted(&mail->mail.mail,
140 "Corrupted cached mime.parts data: %s (parts=%s)",
141 error, binary_to_hex(part_buf->data, part_buf->used));
142 }
143 return parts;
144 }
145
message_parts_have_nuls(const struct message_part * part)146 static bool message_parts_have_nuls(const struct message_part *part)
147 {
148 for (; part != NULL; part = part->next) {
149 if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0)
150 return TRUE;
151 if (part->children != NULL) {
152 if (message_parts_have_nuls(part->children))
153 return TRUE;
154 }
155 }
156 return FALSE;
157 }
158
get_cached_parts(struct index_mail * mail)159 static bool get_cached_parts(struct index_mail *mail)
160 {
161 struct message_part *part;
162
163 if (mail->data.parts != NULL)
164 return TRUE;
165
166 T_BEGIN {
167 part = get_unserialized_parts(mail);
168 } T_END;
169 if (part == NULL)
170 return FALSE;
171
172 /* we know the NULs now, update them */
173 if (message_parts_have_nuls(part)) {
174 mail->mail.mail.has_nuls = TRUE;
175 mail->mail.mail.has_no_nuls = FALSE;
176 } else {
177 mail->mail.mail.has_nuls = FALSE;
178 mail->mail.mail.has_no_nuls = TRUE;
179 }
180
181 mail->data.parts = part;
182 if (index_mail_want_attachment_keywords_on_fetch(mail))
183 index_mail_try_set_attachment_keywords(mail);
184 return TRUE;
185 }
186
index_mail_set_message_parts_corrupted(struct mail * mail,const char * error)187 void index_mail_set_message_parts_corrupted(struct mail *mail, const char *error)
188 {
189 buffer_t *part_buf;
190 const char *parts_str;
191
192 if (get_serialized_parts(INDEX_MAIL(mail), &part_buf) <= 0)
193 parts_str = "";
194 else
195 parts_str = binary_to_hex(part_buf->data, part_buf->used);
196
197 mail_set_cache_corrupted(mail,
198 MAIL_FETCH_MESSAGE_PARTS, t_strdup_printf(
199 "Cached MIME parts don't match message during parsing: %s (parts=%s)",
200 error, parts_str));
201 }
202
index_mail_get_fixed_field(struct index_mail * mail,enum index_cache_field field,void * data,size_t data_size)203 static bool index_mail_get_fixed_field(struct index_mail *mail,
204 enum index_cache_field field,
205 void *data, size_t data_size)
206 {
207 const unsigned int field_idx = mail->ibox->cache_fields[field].idx;
208 buffer_t buf;
209 bool ret;
210
211 buffer_create_from_data(&buf, data, data_size);
212 if (index_mail_cache_lookup_field(mail, &buf, field_idx) <= 0)
213 ret = FALSE;
214 else {
215 i_assert(buf.used == data_size);
216 ret = TRUE;
217 }
218 return ret;
219 }
220
index_mail_get_cached_uoff_t(struct index_mail * mail,enum index_cache_field field,uoff_t * size_r)221 bool index_mail_get_cached_uoff_t(struct index_mail *mail,
222 enum index_cache_field field, uoff_t *size_r)
223 {
224 return index_mail_get_fixed_field(mail, field,
225 size_r, sizeof(*size_r));
226 }
227
index_mail_get_pvt(struct mail * _mail)228 static bool index_mail_get_pvt(struct mail *_mail)
229 {
230 struct mail_private *mail = (struct mail_private *)_mail;
231
232 if (mail->seq_pvt != 0)
233 return TRUE;
234 if (_mail->box->view_pvt == NULL) {
235 /* no private view (set by view syncing) -> no private flags */
236 return FALSE;
237 }
238 if (_mail->saving) {
239 /* mail is still being saved, it has no private flags yet */
240 return FALSE;
241 }
242 i_assert(_mail->uid != 0);
243
244 index_transaction_init_pvt(_mail->transaction);
245 if (!mail_index_lookup_seq(_mail->transaction->view_pvt, _mail->uid,
246 &mail->seq_pvt))
247 mail->seq_pvt = 0;
248 return mail->seq_pvt != 0;
249 }
250
index_mail_get_flags(struct mail * _mail)251 enum mail_flags index_mail_get_flags(struct mail *_mail)
252 {
253 struct mail_private *mail = (struct mail_private *)_mail;
254 const struct mail_index_record *rec;
255 enum mail_flags flags, pvt_flags_mask;
256
257 rec = mail_index_lookup(_mail->transaction->view, _mail->seq);
258 flags = rec->flags & (MAIL_FLAGS_NONRECENT |
259 MAIL_INDEX_MAIL_FLAG_BACKEND);
260
261 if (mailbox_recent_flags_have_uid(_mail->box, _mail->uid))
262 flags |= MAIL_RECENT;
263
264 if (index_mail_get_pvt(_mail)) {
265 /* mailbox has private flags */
266 pvt_flags_mask = mailbox_get_private_flags_mask(_mail->box);
267 flags &= ENUM_NEGATE(pvt_flags_mask);
268 rec = mail_index_lookup(_mail->transaction->view_pvt,
269 mail->seq_pvt);
270 flags |= rec->flags & pvt_flags_mask;
271 }
272 return flags;
273 }
274
index_mail_get_modseq(struct mail * _mail)275 uint64_t index_mail_get_modseq(struct mail *_mail)
276 {
277 struct index_mail *mail = INDEX_MAIL(_mail);
278
279 if (mail->data.modseq != 0)
280 return mail->data.modseq;
281
282 mail_index_modseq_enable(_mail->box->index);
283 mail->data.modseq =
284 mail_index_modseq_lookup(_mail->transaction->view, _mail->seq);
285 return mail->data.modseq;
286 }
287
index_mail_get_pvt_modseq(struct mail * _mail)288 uint64_t index_mail_get_pvt_modseq(struct mail *_mail)
289 {
290 struct index_mail *mail = INDEX_MAIL(_mail);
291
292 if (mail->data.pvt_modseq != 0)
293 return mail->data.pvt_modseq;
294
295 if (mailbox_open_index_pvt(_mail->box) <= 0)
296 return 0;
297 index_transaction_init_pvt(_mail->transaction);
298
299 mail_index_modseq_enable(_mail->box->index_pvt);
300 mail->data.pvt_modseq =
301 mail_index_modseq_lookup(_mail->transaction->view_pvt,
302 _mail->seq);
303 return mail->data.pvt_modseq;
304 }
305
index_mail_get_keywords(struct mail * _mail)306 const char *const *index_mail_get_keywords(struct mail *_mail)
307 {
308 struct index_mail *mail = INDEX_MAIL(_mail);
309 struct index_mail_data *data = &mail->data;
310 const char *const *names;
311 const unsigned int *keyword_indexes;
312 unsigned int i, count, names_count;
313
314 if (array_is_created(&data->keywords))
315 return array_front(&data->keywords);
316
317 (void)index_mail_get_keyword_indexes(_mail);
318
319 keyword_indexes = array_get(&data->keyword_indexes, &count);
320 names = array_get(mail->ibox->keyword_names, &names_count);
321 p_array_init(&data->keywords, mail->mail.data_pool, count + 1);
322 for (i = 0; i < count; i++) {
323 const char *name;
324 i_assert(keyword_indexes[i] < names_count);
325
326 name = names[keyword_indexes[i]];
327 array_push_back(&data->keywords, &name);
328 }
329
330 /* end with NULL */
331 array_append_zero(&data->keywords);
332 return array_front(&data->keywords);
333 }
334
ARRAY_TYPE(keyword_indexes)335 const ARRAY_TYPE(keyword_indexes) *
336 index_mail_get_keyword_indexes(struct mail *_mail)
337 {
338 struct index_mail *mail = INDEX_MAIL(_mail);
339 struct index_mail_data *data = &mail->data;
340
341 if (!array_is_created(&data->keyword_indexes)) {
342 p_array_init(&data->keyword_indexes, mail->mail.data_pool, 32);
343 mail_index_lookup_keywords(_mail->transaction->view,
344 mail->data.seq,
345 &data->keyword_indexes);
346 }
347 return &data->keyword_indexes;
348 }
349
index_mail_get_parts(struct mail * _mail,struct message_part ** parts_r)350 int index_mail_get_parts(struct mail *_mail, struct message_part **parts_r)
351 {
352 struct index_mail *mail = INDEX_MAIL(_mail);
353 struct index_mail_data *data = &mail->data;
354
355 data->cache_fetch_fields |= MAIL_FETCH_MESSAGE_PARTS;
356 if (data->parts != NULL || get_cached_parts(mail)) {
357 *parts_r = data->parts;
358 return 0;
359 }
360
361 if (data->parser_ctx == NULL) {
362 const char *reason =
363 index_mail_cache_reason(_mail, "mime parts");
364 if (index_mail_parse_headers(mail, NULL, reason) < 0)
365 return -1;
366 /* parts may be set now as a result of some plugin */
367 }
368
369 if (data->parts == NULL) {
370 data->save_message_parts = TRUE;
371 if (index_mail_parse_body(mail, 0) < 0)
372 return -1;
373 }
374
375 *parts_r = data->parts;
376 return 0;
377 }
378
index_mail_get_received_date(struct mail * _mail,time_t * date_r)379 int index_mail_get_received_date(struct mail *_mail, time_t *date_r)
380 {
381 struct index_mail *mail = INDEX_MAIL(_mail);
382 struct index_mail_data *data = &mail->data;
383
384 data->cache_fetch_fields |= MAIL_FETCH_RECEIVED_DATE;
385 if (data->received_date == (time_t)-1) {
386 uint32_t t;
387
388 if (index_mail_get_fixed_field(mail, MAIL_CACHE_RECEIVED_DATE,
389 &t, sizeof(t)))
390 data->received_date = t;
391 }
392
393 *date_r = data->received_date;
394 return *date_r == (time_t)-1 ? -1 : 0;
395 }
396
index_mail_get_save_date(struct mail * _mail,time_t * date_r)397 int index_mail_get_save_date(struct mail *_mail, time_t *date_r)
398 {
399 struct index_mail *mail = INDEX_MAIL(_mail);
400 struct index_mail_data *data = &mail->data;
401
402 data->cache_fetch_fields |= MAIL_FETCH_SAVE_DATE;
403 if (data->save_date == (time_t)-1) {
404 uint32_t t;
405
406 if (index_mail_get_fixed_field(mail, MAIL_CACHE_SAVE_DATE,
407 &t, sizeof(t)))
408 data->save_date = t;
409 }
410
411 *date_r = data->save_date;
412 return *date_r == (time_t)-1 ? -1 : 1;
413 }
414
index_mail_cache_sent_date(struct index_mail * mail)415 static int index_mail_cache_sent_date(struct index_mail *mail)
416 {
417 struct index_mail_data *data = &mail->data;
418 const char *str;
419 time_t t;
420 int ret, tz;
421
422 if (data->sent_date.time != (uint32_t)-1)
423 return 0;
424
425 if ((ret = mail_get_first_header(&mail->mail.mail, "Date", &str)) < 0)
426 return ret;
427
428 if (ret == 0 ||
429 !message_date_parse((const unsigned char *)str,
430 strlen(str), &t, &tz)) {
431 /* 0 = not found / invalid */
432 t = 0;
433 tz = 0;
434 }
435 data->sent_date.time = t;
436 data->sent_date.timezone = tz;
437 index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
438 &data->sent_date, sizeof(data->sent_date));
439 return 0;
440 }
441
index_mail_get_date(struct mail * _mail,time_t * date_r,int * timezone_r)442 int index_mail_get_date(struct mail *_mail, time_t *date_r, int *timezone_r)
443 {
444 struct index_mail *mail = INDEX_MAIL(_mail);
445 struct index_mail_data *data = &mail->data;
446 struct mail_sent_date sentdate;
447
448 data->cache_fetch_fields |= MAIL_FETCH_DATE;
449 if (data->sent_date.time != (uint32_t)-1) {
450 *timezone_r = data->sent_date.timezone;
451 *date_r = data->sent_date.time;
452 return 0;
453 }
454
455 if (index_mail_get_fixed_field(mail, MAIL_CACHE_SENT_DATE,
456 &sentdate, sizeof(sentdate)))
457 data->sent_date = sentdate;
458
459 if (index_mail_cache_sent_date(mail) < 0)
460 return -1;
461
462 *timezone_r = data->sent_date.timezone;
463 *date_r = data->sent_date.time;
464 return 0;
465 }
466
get_cached_msgpart_sizes(struct index_mail * mail)467 static bool get_cached_msgpart_sizes(struct index_mail *mail)
468 {
469 struct index_mail_data *data = &mail->data;
470
471 if (data->parts == NULL)
472 (void)get_cached_parts(mail);
473
474 if (data->parts != NULL) {
475 data->hdr_size_set = TRUE;
476 data->hdr_size = data->parts->header_size;
477 data->body_size = data->parts->body_size;
478 data->body_size_set = TRUE;
479 data->virtual_size = data->parts->header_size.virtual_size +
480 data->body_size.virtual_size;
481 data->physical_size = data->parts->header_size.physical_size +
482 data->body_size.physical_size;
483 }
484
485 return data->parts != NULL;
486 }
487
index_mail_get_vsize_extension(struct mail * _mail)488 const uint32_t *index_mail_get_vsize_extension(struct mail *_mail)
489 {
490 const void *idata;
491 bool expunged ATTR_UNUSED;
492
493 mail_index_lookup_ext(_mail->transaction->view, _mail->seq,
494 _mail->box->mail_vsize_ext_id, &idata, &expunged);
495 const uint32_t *vsize = idata;
496 return vsize;
497 }
498
index_mail_try_set_body_size(struct index_mail * mail)499 static void index_mail_try_set_body_size(struct index_mail *mail)
500 {
501 struct index_mail_data *data = &mail->data;
502
503 if (data->hdr_size_set && !data->inexact_total_sizes &&
504 data->physical_size != UOFF_T_MAX &&
505 data->virtual_size != UOFF_T_MAX) {
506 /* We know the total size of this mail and we know the
507 header size, so we can calculate also the body size.
508 However, don't do this if there's a possibility that
509 physical_size or virtual_size don't actually match the
510 mail stream's size (e.g. buggy imapc servers). */
511 if (data->physical_size < data->hdr_size.physical_size) {
512 mail_set_cache_corrupted(&mail->mail.mail,
513 MAIL_FETCH_PHYSICAL_SIZE, t_strdup_printf(
514 "Cached physical size smaller than header size "
515 "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
516 data->physical_size, data->hdr_size.physical_size));
517 } else if (data->virtual_size < data->hdr_size.virtual_size) {
518 mail_set_cache_corrupted(&mail->mail.mail,
519 MAIL_FETCH_VIRTUAL_SIZE, t_strdup_printf(
520 "Cached virtual size smaller than header size "
521 "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
522 data->virtual_size, data->hdr_size.virtual_size));
523 } else {
524 data->body_size.physical_size = data->physical_size -
525 data->hdr_size.physical_size;
526 data->body_size.virtual_size = data->virtual_size -
527 data->hdr_size.virtual_size;
528 data->body_size_set = TRUE;
529 }
530 }
531 }
532
index_mail_get_cached_virtual_size(struct index_mail * mail,uoff_t * size_r)533 bool index_mail_get_cached_virtual_size(struct index_mail *mail, uoff_t *size_r)
534 {
535 struct index_mail_data *data = &mail->data;
536 struct mail *_mail = &mail->mail.mail;
537 uoff_t size;
538 unsigned int idx ATTR_UNUSED;
539
540 /* see if we can get it from index */
541 const uint32_t *vsize = index_mail_get_vsize_extension(_mail);
542
543 data->cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
544 if (data->virtual_size == UOFF_T_MAX && vsize != NULL && *vsize > 0)
545 data->virtual_size = (*vsize)-1;
546 if (data->virtual_size == UOFF_T_MAX) {
547 if (index_mail_get_cached_uoff_t(mail,
548 MAIL_CACHE_VIRTUAL_FULL_SIZE,
549 &size))
550 data->virtual_size = size;
551 else {
552 if (!get_cached_msgpart_sizes(mail))
553 return FALSE;
554 }
555 }
556 index_mail_try_set_body_size(mail);
557 *size_r = data->virtual_size;
558
559 /* if vsize is present and wanted for index, but missing from index
560 add it to index. */
561 if (vsize != NULL && *vsize == 0 &&
562 data->virtual_size < (uint32_t)-1) {
563 uint32_t vsize = data->virtual_size+1;
564 mail_index_update_ext(_mail->transaction->itrans, _mail->seq,
565 _mail->box->mail_vsize_ext_id, &vsize, NULL);
566 }
567
568 return TRUE;
569 }
570
index_mail_get_cached_body_size(struct index_mail * mail)571 static void index_mail_get_cached_body_size(struct index_mail *mail)
572 {
573 struct index_mail_data *data = &mail->data;
574 uoff_t tmp;
575
576 if (!data->hdr_size_set)
577 return;
578
579 /* we've already called get_cached_msgpart_sizes() and it didn't work.
580 try to do this by using cached virtual size and a quick physical
581 size lookup. */
582 if (!index_mail_get_cached_virtual_size(mail, &tmp))
583 return;
584
585 if (!data->body_size_set) {
586 enum mail_lookup_abort old_abort = mail->mail.mail.lookup_abort;
587
588 /* get the physical size, but not if it requires reading
589 through the whole message */
590 if (mail->mail.mail.lookup_abort < MAIL_LOOKUP_ABORT_READ_MAIL)
591 mail->mail.mail.lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL;
592 if (mail_get_physical_size(&mail->mail.mail, &tmp) == 0) {
593 /* we should have everything now. try again. */
594 (void)index_mail_get_cached_virtual_size(mail, &tmp);
595 }
596 mail->mail.mail.lookup_abort = old_abort;
597 }
598 }
599
index_mail_get_virtual_size(struct mail * _mail,uoff_t * size_r)600 int index_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
601 {
602 struct index_mail *mail = INDEX_MAIL(_mail);
603 struct index_mail_data *data = &mail->data;
604 struct message_size hdr_size, body_size;
605 struct istream *input;
606 uoff_t old_offset;
607
608 if (index_mail_get_cached_virtual_size(mail, size_r))
609 return 0;
610
611 old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
612 if (mail_get_stream_because(_mail, &hdr_size, &body_size,
613 index_mail_cache_reason(_mail, "virtual size"), &input) < 0)
614 return -1;
615 i_stream_seek(data->stream, old_offset);
616
617 i_assert(data->virtual_size != UOFF_T_MAX);
618 *size_r = data->virtual_size;
619 return 0;
620 }
621
index_mail_get_physical_size(struct mail * _mail,uoff_t * size_r)622 int index_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
623 {
624 struct index_mail *mail = INDEX_MAIL(_mail);
625 struct index_mail_data *data = &mail->data;
626 uoff_t size;
627
628 if (_mail->lookup_abort != MAIL_LOOKUP_ABORT_NOT_IN_CACHE &&
629 _mail->lookup_abort != MAIL_LOOKUP_ABORT_READ_MAIL) {
630 /* If size.physical isn't in cache yet, add it. Do this only
631 when the caller appears to actually want it to be cached.
632 We don't want to cache the size when coming in here from
633 i_stream_mail_try_get_cached_size() or
634 index_mail_get_cached_body_size(). */
635 data->cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
636 }
637 if (data->physical_size == UOFF_T_MAX) {
638 if (index_mail_get_cached_uoff_t(mail,
639 MAIL_CACHE_PHYSICAL_FULL_SIZE,
640 &size))
641 data->physical_size = size;
642 else
643 (void)get_cached_msgpart_sizes(mail);
644 }
645 *size_r = data->physical_size;
646 return *size_r == UOFF_T_MAX ? -1 : 0;
647 }
648
index_mail_cache_add(struct index_mail * mail,enum index_cache_field field,const void * data,size_t data_size)649 void index_mail_cache_add(struct index_mail *mail, enum index_cache_field field,
650 const void *data, size_t data_size)
651 {
652 index_mail_cache_add_idx(mail, mail->ibox->cache_fields[field].idx,
653 data, data_size);
654 }
655
index_mail_cache_add_idx(struct index_mail * mail,unsigned int field_idx,const void * data,size_t data_size)656 void index_mail_cache_add_idx(struct index_mail *mail, unsigned int field_idx,
657 const void *data, size_t data_size)
658 {
659 struct mail *_mail = &mail->mail.mail;
660 const struct mail_storage_settings *set = _mail->box->storage->set;
661 const struct mail_index_header *hdr;
662
663 if (set->mail_cache_min_mail_count > 0) {
664 /* First check if we've configured caching not to be used with
665 low enough message count. */
666 hdr = mail_index_get_header(_mail->transaction->view);
667 if (hdr->messages_count < set->mail_cache_min_mail_count)
668 return;
669 }
670
671 if (!mail->data.no_caching &&
672 mail->data.dont_cache_field_idx != field_idx &&
673 !_mail->box->mail_cache_disabled) {
674 mail_cache_add(_mail->transaction->cache_trans, _mail->seq,
675 field_idx, data, data_size);
676 }
677 }
678
index_mail_cache_pop3_data(struct mail * _mail,const char * uidl,uint32_t order)679 void index_mail_cache_pop3_data(struct mail *_mail,
680 const char *uidl, uint32_t order)
681 {
682 struct index_mail *mail = INDEX_MAIL(_mail);
683
684 if (uidl != NULL)
685 index_mail_cache_add(mail, MAIL_CACHE_POP3_UIDL,
686 uidl, strlen(uidl));
687
688 if (order != 0)
689 index_mail_cache_add(mail, MAIL_CACHE_POP3_ORDER,
690 &order, sizeof(order));
691 }
692
parse_bodystructure_part_header(struct message_part * part,struct message_header_line * hdr,pool_t pool)693 static void parse_bodystructure_part_header(struct message_part *part,
694 struct message_header_line *hdr,
695 pool_t pool)
696 {
697 message_part_data_parse_from_header(pool, part, hdr);
698 }
699
want_plain_bodystructure_cached(struct index_mail * mail)700 static bool want_plain_bodystructure_cached(struct index_mail *mail)
701 {
702 const unsigned int cache_field_body =
703 mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODY].idx;
704 const unsigned int cache_field_bodystructure =
705 mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;
706 struct mail *_mail = &mail->mail.mail;
707
708 if ((mail->data.wanted_fields & (MAIL_FETCH_IMAP_BODY |
709 MAIL_FETCH_IMAP_BODYSTRUCTURE)) != 0)
710 return TRUE;
711
712 if (mail_cache_field_want_add(_mail->transaction->cache_trans,
713 _mail->seq, cache_field_body))
714 return TRUE;
715 if (mail_cache_field_want_add(_mail->transaction->cache_trans,
716 _mail->seq, cache_field_bodystructure))
717 return TRUE;
718 return FALSE;
719 }
720
index_mail_body_parsed_cache_flags(struct index_mail * mail)721 static void index_mail_body_parsed_cache_flags(struct index_mail *mail)
722 {
723 struct mail *_mail = &mail->mail.mail;
724 struct index_mail_data *data = &mail->data;
725 unsigned int cache_flags_idx;
726 uint32_t cache_flags = data->cache_flags;
727 bool want_cached;
728
729 cache_flags_idx = mail->ibox->cache_fields[MAIL_CACHE_FLAGS].idx;
730 want_cached = mail_cache_field_want_add(_mail->transaction->cache_trans,
731 _mail->seq, cache_flags_idx);
732
733 if (data->parsed_bodystructure &&
734 message_part_data_is_plain_7bit(data->parts) &&
735 (want_cached || want_plain_bodystructure_cached(mail))) {
736 cache_flags |= MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII;
737 /* we need message_parts cached to be able to
738 actually use it in BODY/BODYSTRUCTURE reply */
739 want_cached = TRUE;
740 data->save_message_parts = TRUE;
741 }
742
743 /* cache flags should never get unset as long as the message doesn't
744 change, but try to handle it anyway */
745 cache_flags &= ENUM_NEGATE(MAIL_CACHE_FLAG_BINARY_HEADER |
746 MAIL_CACHE_FLAG_BINARY_BODY |
747 MAIL_CACHE_FLAG_HAS_NULS |
748 MAIL_CACHE_FLAG_HAS_NO_NULS);
749 if (message_parts_have_nuls(data->parts)) {
750 _mail->has_nuls = TRUE;
751 _mail->has_no_nuls = FALSE;
752 cache_flags |= MAIL_CACHE_FLAG_HAS_NULS;
753 } else {
754 _mail->has_nuls = FALSE;
755 _mail->has_no_nuls = TRUE;
756 cache_flags |= MAIL_CACHE_FLAG_HAS_NO_NULS;
757 }
758
759 if (data->hdr_size.virtual_size == data->hdr_size.physical_size)
760 cache_flags |= MAIL_CACHE_FLAG_BINARY_HEADER;
761 if (data->body_size.virtual_size == data->body_size.physical_size)
762 cache_flags |= MAIL_CACHE_FLAG_BINARY_BODY;
763
764 if (cache_flags != data->cache_flags && want_cached) {
765 index_mail_cache_add_idx(mail, cache_flags_idx,
766 &cache_flags, sizeof(cache_flags));
767 }
768 data->cache_flags = cache_flags;
769 }
770
index_mail_body_parsed_cache_message_parts(struct index_mail * mail)771 static void index_mail_body_parsed_cache_message_parts(struct index_mail *mail)
772 {
773 struct mail *_mail = &mail->mail.mail;
774 struct index_mail_data *data = &mail->data;
775 const unsigned int cache_field =
776 mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx;
777 enum mail_cache_decision_type decision;
778 buffer_t *buffer;
779
780 if (data->messageparts_saved_to_cache ||
781 mail_cache_field_exists(_mail->transaction->cache_view, _mail->seq,
782 cache_field) != 0) {
783 /* already cached */
784 return;
785 }
786
787 decision = mail_cache_field_get_decision(_mail->box->cache,
788 cache_field);
789 if (decision == (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) {
790 /* we never want it cached */
791 return;
792 }
793 if (decision == MAIL_CACHE_DECISION_NO &&
794 !data->save_message_parts &&
795 (data->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) == 0) {
796 /* we didn't really care about the message parts themselves,
797 just wanted to use something that depended on it */
798 return;
799 }
800
801 T_BEGIN {
802 buffer = t_buffer_create(1024);
803 message_part_serialize(mail->data.parts, buffer);
804 index_mail_cache_add_idx(mail, cache_field,
805 buffer->data, buffer->used);
806 } T_END;
807
808 data->messageparts_saved_to_cache = TRUE;
809 }
810
811 static int
index_mail_write_bodystructure(struct index_mail * mail,string_t * str,bool extended)812 index_mail_write_bodystructure(struct index_mail *mail, string_t *str,
813 bool extended)
814 {
815 const char *error;
816
817 if (imap_bodystructure_write(mail->data.parts, str, extended,
818 &error) < 0) {
819 mail_set_cache_corrupted(&mail->mail.mail,
820 MAIL_FETCH_MESSAGE_PARTS, error);
821 return -1;
822 }
823 return 0;
824 }
825
826 static void
index_mail_body_parsed_cache_bodystructure(struct index_mail * mail,enum index_cache_field field)827 index_mail_body_parsed_cache_bodystructure(struct index_mail *mail,
828 enum index_cache_field field)
829 {
830 struct mail *_mail = &mail->mail.mail;
831 struct index_mail_data *data = &mail->data;
832 const unsigned int cache_field_parts =
833 mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx;
834 const unsigned int cache_field_body =
835 mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODY].idx;
836 const unsigned int cache_field_bodystructure =
837 mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;
838 enum mail_cache_decision_type dec;
839 string_t *str;
840 bool bodystructure_cached = FALSE;
841 bool plain_bodystructure = FALSE;
842 bool cache_bodystructure, cache_body;
843
844 if ((data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0) {
845 if (data->messageparts_saved_to_cache ||
846 mail_cache_field_exists(_mail->transaction->cache_view,
847 _mail->seq, cache_field_parts) > 0) {
848 /* cached it as flag + message_parts */
849 plain_bodystructure = TRUE;
850 }
851 }
852
853 if (!data->parsed_bodystructure)
854 return;
855 i_assert(data->parts != NULL);
856
857 /* If BODY is fetched first but BODYSTRUCTURE is also wanted, we don't
858 normally want to first cache BODY and then BODYSTRUCTURE. So check
859 the wanted_fields also in here. */
860 if (plain_bodystructure)
861 cache_bodystructure = FALSE;
862 else if (field == MAIL_CACHE_IMAP_BODYSTRUCTURE ||
863 (data->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) {
864 cache_bodystructure =
865 mail_cache_field_can_add(_mail->transaction->cache_trans,
866 _mail->seq, cache_field_bodystructure);
867 } else {
868 cache_bodystructure =
869 mail_cache_field_want_add(_mail->transaction->cache_trans,
870 _mail->seq, cache_field_bodystructure);
871 }
872 if (cache_bodystructure) {
873 str = str_new(mail->mail.data_pool, 128);
874 if (index_mail_write_bodystructure(mail, str, TRUE) == 0) {
875 data->bodystructure = str_c(str);
876 index_mail_cache_add(mail, MAIL_CACHE_IMAP_BODYSTRUCTURE,
877 str_c(str), str_len(str));
878 bodystructure_cached = TRUE;
879 }
880 } else {
881 bodystructure_cached =
882 mail_cache_field_exists(_mail->transaction->cache_view,
883 _mail->seq, cache_field_bodystructure) > 0;
884 }
885
886 /* normally don't cache both BODY and BODYSTRUCTURE, but do it
887 if BODY is forced to be cached */
888 dec = mail_cache_field_get_decision(_mail->box->cache,
889 cache_field_body);
890 if (plain_bodystructure ||
891 (bodystructure_cached &&
892 (dec != (MAIL_CACHE_DECISION_FORCED | MAIL_CACHE_DECISION_YES))))
893 cache_body = FALSE;
894 else if (field == MAIL_CACHE_IMAP_BODY) {
895 cache_body =
896 mail_cache_field_can_add(_mail->transaction->cache_trans,
897 _mail->seq, cache_field_body);
898 } else {
899 cache_body =
900 mail_cache_field_want_add(_mail->transaction->cache_trans,
901 _mail->seq, cache_field_body);
902 }
903
904 if (cache_body) {
905 str = str_new(mail->mail.data_pool, 128);
906 if (index_mail_write_bodystructure(mail, str, FALSE) == 0) {
907 data->body = str_c(str);
908 index_mail_cache_add(mail, MAIL_CACHE_IMAP_BODY,
909 str_c(str), str_len(str));
910 }
911 }
912 }
913
index_mail_want_cache(struct index_mail * mail,enum index_cache_field field)914 bool index_mail_want_cache(struct index_mail *mail, enum index_cache_field field)
915 {
916 struct mail *_mail = &mail->mail.mail;
917 enum mail_fetch_field fetch_field;
918 unsigned int cache_field;
919
920 switch (field) {
921 case MAIL_CACHE_SENT_DATE:
922 fetch_field = MAIL_FETCH_DATE;
923 break;
924 case MAIL_CACHE_RECEIVED_DATE:
925 fetch_field = MAIL_FETCH_RECEIVED_DATE;
926 break;
927 case MAIL_CACHE_SAVE_DATE:
928 fetch_field = MAIL_FETCH_SAVE_DATE;
929 break;
930 case MAIL_CACHE_VIRTUAL_FULL_SIZE:
931 fetch_field = MAIL_FETCH_VIRTUAL_SIZE;
932 break;
933 case MAIL_CACHE_PHYSICAL_FULL_SIZE:
934 fetch_field = MAIL_FETCH_PHYSICAL_SIZE;
935 break;
936 case MAIL_CACHE_BODY_SNIPPET:
937 fetch_field = MAIL_FETCH_BODY_SNIPPET;
938 break;
939 default:
940 i_unreached();
941 }
942
943 if ((mail->data.dont_cache_fetch_fields & fetch_field) != 0)
944 return FALSE;
945
946 /* If a field has been explicitly requested to be fetched, it's
947 included in data.cache_fetch_fields. In that case use _can_add() to
948 add it to the cache file if at all possible. Otherwise, use
949 _want_add() to use previous caching decisions. */
950 cache_field = mail->ibox->cache_fields[field].idx;
951 if ((mail->data.cache_fetch_fields & fetch_field) != 0) {
952 return mail_cache_field_can_add(_mail->transaction->cache_trans,
953 _mail->seq, cache_field);
954 } else {
955 return mail_cache_field_want_add(_mail->transaction->cache_trans,
956 _mail->seq, cache_field);
957 }
958 }
959
index_mail_save_finish_make_snippet(struct index_mail * mail)960 static void index_mail_save_finish_make_snippet(struct index_mail *mail)
961 {
962 if (mail->data.save_body_snippet) {
963 if (index_mail_write_body_snippet(mail) < 0)
964 return;
965 mail->data.save_body_snippet = FALSE;
966 }
967
968 if (mail->data.body_snippet != NULL &&
969 index_mail_want_cache(mail, MAIL_CACHE_BODY_SNIPPET)) {
970 index_mail_cache_add(mail, MAIL_CACHE_BODY_SNIPPET,
971 mail->data.body_snippet,
972 strlen(mail->data.body_snippet));
973 }
974 }
975
index_mail_cache_sizes(struct index_mail * mail)976 static void index_mail_cache_sizes(struct index_mail *mail)
977 {
978 struct mail *_mail = &mail->mail.mail;
979 struct mail_index_view *view = _mail->transaction->view;
980
981 static enum index_cache_field size_fields[] = {
982 MAIL_CACHE_VIRTUAL_FULL_SIZE,
983 MAIL_CACHE_PHYSICAL_FULL_SIZE
984 };
985 uoff_t sizes[N_ELEMENTS(size_fields)];
986 unsigned int i;
987 uint32_t vsize;
988 uint32_t idx ATTR_UNUSED;
989
990 sizes[0] = mail->data.virtual_size;
991 sizes[1] = mail->data.physical_size;
992
993 /* store the virtual size in index if
994 extension for it exists or
995 extension for box virtual size exists and
996 size fits and is present and
997 size is not cached or
998 cached size differs
999 */
1000 if ((mail_index_map_get_ext_idx(view->index->map, _mail->box->mail_vsize_ext_id, &idx) ||
1001 mail_index_map_get_ext_idx(view->index->map, _mail->box->vsize_hdr_ext_id, &idx)) &&
1002 (sizes[0] != UOFF_T_MAX &&
1003 sizes[0] < (uint32_t)-1)) {
1004 const uint32_t *vsize_ext =
1005 index_mail_get_vsize_extension(_mail);
1006 /* vsize = 0 means it's not present in index, consult cache.
1007 we store vsize for every +4GB-1 mail to cache because
1008 index can only hold 2^32-1 size. Cache will not be used
1009 when vsize is stored in index. */
1010 vsize = sizes[0] + 1;
1011 if (vsize_ext == NULL || vsize != *vsize_ext) {
1012 mail_index_update_ext(_mail->transaction->itrans, _mail->seq,
1013 _mail->box->mail_vsize_ext_id, &vsize, NULL);
1014 }
1015 /* it's already in index, so don't update cache */
1016 sizes[0] = UOFF_T_MAX;
1017 }
1018
1019 for (i = 0; i < N_ELEMENTS(size_fields); i++) {
1020 if (sizes[i] != UOFF_T_MAX &&
1021 index_mail_want_cache(mail, size_fields[i])) {
1022 index_mail_cache_add(mail, size_fields[i],
1023 &sizes[i], sizeof(sizes[i]));
1024 }
1025 }
1026 }
1027
index_mail_cache_dates(struct index_mail * mail)1028 static void index_mail_cache_dates(struct index_mail *mail)
1029 {
1030 static enum index_cache_field date_fields[] = {
1031 MAIL_CACHE_RECEIVED_DATE,
1032 MAIL_CACHE_SAVE_DATE
1033 };
1034 time_t dates[N_ELEMENTS(date_fields)];
1035 unsigned int i;
1036 uint32_t t;
1037
1038 dates[0] = mail->data.received_date;
1039 dates[1] = mail->mail.mail.saving ? ioloop_time :
1040 mail->data.save_date;
1041
1042 for (i = 0; i < N_ELEMENTS(date_fields); i++) {
1043 if (dates[i] != (time_t)-1 &&
1044 index_mail_want_cache(mail, date_fields[i])) {
1045 t = dates[i];
1046 index_mail_cache_add(mail, date_fields[i],
1047 &t, sizeof(t));
1048 }
1049 }
1050
1051 if (mail->data.sent_date_parsed &&
1052 index_mail_want_cache(mail, MAIL_CACHE_SENT_DATE))
1053 (void)index_mail_cache_sent_date(mail);
1054 }
1055
1056 static struct message_part *
index_mail_find_first_text_mime_part(struct message_part * parts)1057 index_mail_find_first_text_mime_part(struct message_part *parts)
1058 {
1059 struct message_part_data *body_data = parts->data;
1060 struct message_part *part;
1061
1062 i_assert(body_data != NULL);
1063
1064 if (body_data->content_type == NULL ||
1065 strcasecmp(body_data->content_type, "text") == 0) {
1066 /* use any text/ part, even if we don't know what exactly
1067 it is. */
1068 return parts;
1069 }
1070 if (strcasecmp(body_data->content_type, "multipart") != 0) {
1071 /* for now we support only text Content-Types */
1072 return NULL;
1073 }
1074
1075 if (strcasecmp(body_data->content_subtype, "alternative") == 0) {
1076 /* text/plain > text/html > text/ */
1077 struct message_part *html_part = NULL, *text_part = NULL;
1078
1079 for (part = parts->children; part != NULL; part = part->next) {
1080 struct message_part_data *sub_body_data =
1081 part->data;
1082
1083 i_assert(sub_body_data != NULL);
1084
1085 if (sub_body_data->content_type == NULL ||
1086 strcasecmp(sub_body_data->content_type, "text") == 0) {
1087 if (sub_body_data->content_subtype == NULL ||
1088 strcasecmp(sub_body_data->content_subtype, "plain") == 0)
1089 return part;
1090 if (strcasecmp(sub_body_data->content_subtype, "html") == 0)
1091 html_part = part;
1092 else
1093 text_part = part;
1094 }
1095 }
1096 return html_part != NULL ? html_part : text_part;
1097 }
1098 /* find the first usable MIME part */
1099 for (part = parts->children; part != NULL; part = part->next) {
1100 struct message_part *subpart =
1101 index_mail_find_first_text_mime_part(part);
1102 if (subpart != NULL)
1103 return subpart;
1104 }
1105 return NULL;
1106 }
1107
index_mail_write_body_snippet(struct index_mail * mail)1108 static int index_mail_write_body_snippet(struct index_mail *mail)
1109 {
1110 struct message_part *part;
1111 struct istream *input;
1112 uoff_t old_offset;
1113 string_t *str;
1114 int ret;
1115
1116 i_assert(mail->data.parsed_bodystructure);
1117
1118 part = index_mail_find_first_text_mime_part(mail->data.parts);
1119 if (part == NULL) {
1120 mail->data.body_snippet = BODY_SNIPPET_ALGO_V1;
1121 return 0;
1122 }
1123
1124 old_offset = mail->data.stream == NULL ? 0 : mail->data.stream->v_offset;
1125 const char *reason = index_mail_cache_reason(&mail->mail.mail, "snippet");
1126 if (mail_get_stream_because(&mail->mail.mail, NULL, NULL, reason, &input) < 0)
1127 return -1;
1128 i_assert(mail->data.stream != NULL);
1129
1130 i_stream_seek(input, part->physical_pos);
1131 input = i_stream_create_limit(input, part->header_size.physical_size +
1132 part->body_size.physical_size);
1133
1134 str = str_new(mail->mail.data_pool, 128);
1135 str_append(str, BODY_SNIPPET_ALGO_V1);
1136 ret = message_snippet_generate(input, BODY_SNIPPET_MAX_CHARS, str);
1137 if (ret == 0)
1138 mail->data.body_snippet = str_c(str);
1139 i_stream_destroy(&input);
1140
1141 i_stream_seek(mail->data.stream, old_offset);
1142 return ret;
1143 }
1144
1145 static int
index_mail_parse_body_finish(struct index_mail * mail,enum index_cache_field field,bool success)1146 index_mail_parse_body_finish(struct index_mail *mail,
1147 enum index_cache_field field, bool success)
1148 {
1149 struct istream *parser_input = mail->data.parser_input;
1150 const struct mail_storage_settings *mail_set =
1151 mailbox_get_settings(mail->mail.mail.box);
1152 const char *error = NULL;
1153 int ret;
1154
1155 if (parser_input == NULL) {
1156 ret = message_parser_deinit_from_parts(&mail->data.parser_ctx,
1157 &mail->data.parts, &error) < 0 ? 0 : 1;
1158 } else {
1159 mail->data.parser_input = NULL;
1160 i_stream_ref(parser_input);
1161 ret = message_parser_deinit_from_parts(&mail->data.parser_ctx,
1162 &mail->data.parts, &error) < 0 ? 0 : 1;
1163 if (success && (parser_input->stream_errno == 0 ||
1164 parser_input->stream_errno == EPIPE)) {
1165 /* do one final read, which verifies that the message
1166 size is correct. */
1167 if (i_stream_read(parser_input) != -1 ||
1168 i_stream_have_bytes_left(parser_input))
1169 i_unreached();
1170 }
1171 /* EPIPE = input already closed. allow the caller to
1172 decide if that is an error or not. (for example we
1173 could be coming here from IMAP APPEND when IMAP
1174 client has closed the connection too early. we
1175 don't want to log an error in that case.)
1176 Note that EPIPE may also come from istream-mail which
1177 detects a corrupted message size. Either way, the
1178 body wasn't successfully parsed. */
1179 if (parser_input->stream_errno == 0)
1180 ;
1181 else if (parser_input->stream_errno == EPIPE)
1182 ret = -1;
1183 else {
1184 index_mail_stream_log_failure_for(mail, parser_input);
1185 ret = -1;
1186 }
1187 i_stream_unref(&parser_input);
1188 }
1189 if (ret <= 0) {
1190 if (ret == 0) {
1191 i_assert(error != NULL);
1192 index_mail_set_message_parts_corrupted(&mail->mail.mail, error);
1193 }
1194 mail->data.parts = NULL;
1195 mail->data.parsed_bodystructure = FALSE;
1196 if (mail->data.save_bodystructure_body)
1197 mail->data.save_bodystructure_header = TRUE;
1198 if (mail->data.header_parser_initialized)
1199 index_mail_parse_header_deinit(mail);
1200 return -1;
1201 }
1202 if (mail->data.header_parser_initialized) {
1203 i_assert(!success);
1204 index_mail_parse_header_deinit(mail);
1205 }
1206
1207 if (mail->data.save_bodystructure_body) {
1208 mail->data.parsed_bodystructure = TRUE;
1209 mail->data.save_bodystructure_header = FALSE;
1210 mail->data.save_bodystructure_body = FALSE;
1211 i_assert(mail->data.parts != NULL);
1212 }
1213
1214 if (mail->data.no_caching) {
1215 /* if we're here because we aborted parsing, don't get any
1216 further or we may crash while generating output from
1217 incomplete data */
1218 return 0;
1219 }
1220
1221 (void)get_cached_msgpart_sizes(mail);
1222
1223 index_mail_body_parsed_cache_flags(mail);
1224 index_mail_body_parsed_cache_message_parts(mail);
1225 index_mail_body_parsed_cache_bodystructure(mail, field);
1226 index_mail_cache_sizes(mail);
1227 index_mail_cache_dates(mail);
1228 if (mail_set->parsed_mail_attachment_detection_add_flags &&
1229 !mail_has_attachment_keywords(&mail->mail.mail))
1230 index_mail_try_set_attachment_keywords(mail);
1231 return 0;
1232 }
1233
index_mail_stream_log_failure(struct index_mail * mail)1234 static void index_mail_stream_log_failure(struct index_mail *mail)
1235 {
1236 index_mail_stream_log_failure_for(mail, mail->data.stream);
1237 }
1238
index_mail_stream_check_failure(struct index_mail * mail)1239 int index_mail_stream_check_failure(struct index_mail *mail)
1240 {
1241 if (mail->data.stream->stream_errno == 0)
1242 return 0;
1243 index_mail_stream_log_failure(mail);
1244 return -1;
1245 }
1246
index_mail_refresh_expunged(struct mail * mail)1247 void index_mail_refresh_expunged(struct mail *mail)
1248 {
1249 mail_index_refresh(mail->box->index);
1250 if (mail_index_is_expunged(mail->transaction->view, mail->seq))
1251 mail_set_expunged(mail);
1252 }
1253
index_mail_stream_log_failure_for(struct index_mail * mail,struct istream * input)1254 void index_mail_stream_log_failure_for(struct index_mail *mail,
1255 struct istream *input)
1256 {
1257 struct mail *_mail = &mail->mail.mail;
1258
1259 i_assert(input->stream_errno != 0);
1260
1261 if (input->stream_errno == ENOENT) {
1262 /* was the mail just expunged? we could get here especially if
1263 external attachments are used and the attachment is deleted
1264 before we've opened the file. */
1265 index_mail_refresh_expunged(_mail);
1266 if (_mail->expunged)
1267 return;
1268 }
1269
1270 const char *old_error =
1271 mailbox_get_last_internal_error(_mail->box, NULL);
1272 const char *new_error = t_strdup_printf("read(%s) failed: %s",
1273 i_stream_get_name(input), i_stream_get_error(input));
1274
1275 if (mail->data.istream_error_logged &&
1276 strstr(old_error, new_error) != NULL) {
1277 /* Avoid logging the same istream error multiple times
1278 (even if the read reason is different). The old_error begins
1279 with the UID=n prefix, which we can ignore since we know
1280 that this mail already logged a critical error, so it has
1281 to be about this same mail. */
1282 return;
1283 }
1284 mail->data.istream_error_logged = TRUE;
1285 mail_set_critical(_mail, "%s (read reason=%s)", new_error,
1286 mail->mail.get_stream_reason == NULL ? "" :
1287 mail->mail.get_stream_reason);
1288 }
1289
index_mail_parse_body(struct index_mail * mail,enum index_cache_field field)1290 static int index_mail_parse_body(struct index_mail *mail,
1291 enum index_cache_field field)
1292 {
1293 struct index_mail_data *data = &mail->data;
1294 uoff_t old_offset;
1295 int ret;
1296
1297 i_assert(data->parser_ctx != NULL);
1298
1299 old_offset = data->stream->v_offset;
1300 i_stream_seek(data->stream, data->hdr_size.physical_size);
1301
1302 if (data->save_bodystructure_body) {
1303 /* bodystructure header is parsed, we want the body's mime
1304 headers too */
1305 i_assert(data->parsed_bodystructure_header);
1306 message_parser_parse_body(data->parser_ctx,
1307 parse_bodystructure_part_header,
1308 mail->mail.data_pool);
1309 } else {
1310 message_parser_parse_body(data->parser_ctx,
1311 *null_message_part_header_callback, NULL);
1312 }
1313 ret = index_mail_stream_check_failure(mail);
1314 if (index_mail_parse_body_finish(mail, field, TRUE) < 0)
1315 ret = -1;
1316
1317 i_stream_seek(data->stream, old_offset);
1318 return ret;
1319 }
1320
index_mail_stream_destroy_callback(struct index_mail * mail)1321 static void index_mail_stream_destroy_callback(struct index_mail *mail)
1322 {
1323 i_assert(mail->data.destroying_stream);
1324
1325 mail->data.destroying_stream = FALSE;
1326 }
1327
index_mail_set_read_buffer_size(struct mail * _mail,struct istream * input)1328 void index_mail_set_read_buffer_size(struct mail *_mail, struct istream *input)
1329 {
1330 struct index_mail *mail = INDEX_MAIL(_mail);
1331 unsigned int block_size;
1332
1333 i_stream_set_max_buffer_size(input, MAIL_READ_FULL_BLOCK_SIZE);
1334 block_size = (mail->data.access_part & (READ_BODY | PARSE_BODY)) != 0 ?
1335 MAIL_READ_FULL_BLOCK_SIZE : MAIL_READ_HDR_BLOCK_SIZE;
1336 i_stream_set_init_buffer_size(input, block_size);
1337 }
1338
index_mail_init_stream(struct index_mail * mail,struct message_size * hdr_size,struct message_size * body_size,struct istream ** stream_r)1339 int index_mail_init_stream(struct index_mail *mail,
1340 struct message_size *hdr_size,
1341 struct message_size *body_size,
1342 struct istream **stream_r)
1343 {
1344 struct mail *_mail = &mail->mail.mail;
1345 struct index_mail_data *data = &mail->data;
1346 struct istream *input;
1347 bool has_nuls, body_size_from_stream = FALSE;
1348 int ret;
1349
1350 _mail->mail_stream_opened = TRUE;
1351
1352 if (!data->initialized_wrapper_stream &&
1353 _mail->transaction->stats_track) {
1354 input = i_stream_create_mail(_mail, data->stream,
1355 !data->stream_has_only_header);
1356 i_stream_unref(&data->stream);
1357 data->stream = input;
1358 data->initialized_wrapper_stream = TRUE;
1359 }
1360
1361 if (!data->destroy_callback_set) {
1362 /* do this only once in case a plugin changes the stream.
1363 otherwise the check would break. */
1364 data->destroy_callback_set = TRUE;
1365 i_stream_add_destroy_callback(data->stream,
1366 index_mail_stream_destroy_callback, mail);
1367 }
1368
1369 bool want_attachment_kw =
1370 index_mail_want_attachment_keywords_on_fetch(mail);
1371 if (want_attachment_kw)
1372 data->access_part |= PARSE_HDR | PARSE_BODY;
1373
1374 if (hdr_size != NULL || body_size != NULL)
1375 (void)get_cached_msgpart_sizes(mail);
1376
1377 bool want_body_parsing = want_attachment_kw ||
1378 (body_size != NULL && !data->body_size_set &&
1379 (data->access_part & PARSE_BODY) != 0);
1380
1381 if (hdr_size != NULL || body_size != NULL || want_body_parsing) {
1382 i_stream_seek(data->stream, 0);
1383 if (!data->hdr_size_set || want_body_parsing) {
1384 if ((data->access_part & (PARSE_HDR | PARSE_BODY)) != 0) {
1385 (void)get_cached_parts(mail);
1386 if (index_mail_parse_headers_internal(mail, NULL) < 0)
1387 return -1;
1388 } else {
1389 if (message_get_header_size(data->stream,
1390 &data->hdr_size,
1391 &has_nuls) < 0) {
1392 index_mail_stream_log_failure(mail);
1393 return -1;
1394 }
1395 data->hdr_size_set = TRUE;
1396 }
1397 }
1398
1399 if (hdr_size != NULL)
1400 *hdr_size = data->hdr_size;
1401 }
1402
1403 if (body_size != NULL || want_body_parsing) {
1404 if (!data->body_size_set && body_size != NULL)
1405 index_mail_get_cached_body_size(mail);
1406 if (!data->body_size_set || want_body_parsing) {
1407 i_stream_seek(data->stream,
1408 data->hdr_size.physical_size);
1409 if ((data->access_part & PARSE_BODY) != 0) {
1410 if (index_mail_parse_body(mail, 0) < 0)
1411 return -1;
1412 } else {
1413 if (message_get_body_size(data->stream,
1414 &data->body_size,
1415 &has_nuls) < 0) {
1416 index_mail_stream_log_failure(mail);
1417 return -1;
1418 }
1419 data->body_size_set = TRUE;
1420 }
1421 body_size_from_stream = TRUE;
1422 }
1423
1424 if (body_size != NULL)
1425 *body_size = data->body_size;
1426 }
1427
1428 if (data->hdr_size_set && data->body_size_set) {
1429 data->virtual_size = data->hdr_size.virtual_size +
1430 data->body_size.virtual_size;
1431 data->physical_size = data->hdr_size.physical_size +
1432 data->body_size.physical_size;
1433 if (body_size_from_stream) {
1434 /* the sizes were just calculated */
1435 data->inexact_total_sizes = FALSE;
1436 }
1437 } else {
1438 /* If body_size==NULL, the caller doesn't care about it.
1439 However, try to set it anyway if it can be calculated. */
1440 index_mail_try_set_body_size(mail);
1441 }
1442 ret = index_mail_stream_check_failure(mail);
1443
1444 i_stream_seek(data->stream, 0);
1445 if (ret < 0)
1446 return -1;
1447 *stream_r = data->stream;
1448 return 0;
1449 }
1450
1451 static int
index_mail_parse_bodystructure_full(struct index_mail * mail,enum index_cache_field field)1452 index_mail_parse_bodystructure_full(struct index_mail *mail,
1453 enum index_cache_field field)
1454 {
1455 struct index_mail_data *data = &mail->data;
1456
1457 if ((data->save_bodystructure_header &&
1458 !data->parsed_bodystructure_header) ||
1459 !data->save_bodystructure_body ||
1460 field == MAIL_CACHE_BODY_SNIPPET) {
1461 /* we haven't parsed the header yet */
1462 const char *reason =
1463 index_mail_cache_reason(&mail->mail.mail, "bodystructure");
1464 bool orig_bodystructure_header =
1465 data->save_bodystructure_header;
1466 bool orig_bodystructure_body =
1467 data->save_bodystructure_body;
1468 data->save_bodystructure_header = TRUE;
1469 data->save_bodystructure_body = TRUE;
1470 (void)get_cached_parts(mail);
1471 if (index_mail_parse_headers(mail, NULL, reason) < 0) {
1472 data->save_bodystructure_header =
1473 orig_bodystructure_header;
1474 data->save_bodystructure_body =
1475 orig_bodystructure_body;
1476 return -1;
1477 }
1478 i_assert(data->parser_ctx != NULL);
1479 }
1480
1481 return index_mail_parse_body(mail, field);
1482 }
1483
index_mail_parse_bodystructure(struct index_mail * mail,enum index_cache_field field)1484 static int index_mail_parse_bodystructure(struct index_mail *mail,
1485 enum index_cache_field field)
1486 {
1487 struct index_mail_data *data = &mail->data;
1488 string_t *str;
1489
1490 if (data->parsed_bodystructure && field != MAIL_CACHE_BODY_SNIPPET) {
1491 /* we have everything parsed already, but just not written to
1492 a string */
1493 index_mail_body_parsed_cache_bodystructure(mail, field);
1494 } else {
1495 if (index_mail_parse_bodystructure_full(mail, field) < 0)
1496 return -1;
1497 if (data->parts == NULL) {
1498 /* Corrupted mime.parts detected. Retry by parsing
1499 the mail. */
1500 data->parsed_bodystructure = FALSE;
1501 data->parsed_bodystructure_header = FALSE;
1502 data->save_bodystructure_header = TRUE;
1503 data->save_bodystructure_body = TRUE;
1504 if (index_mail_parse_bodystructure_full(mail, field) < 0)
1505 return -1;
1506 }
1507 }
1508 i_assert(data->parts != NULL);
1509
1510 /* if we didn't want to have the body(structure) cached,
1511 it's still not written. */
1512 switch (field) {
1513 case MAIL_CACHE_IMAP_BODY:
1514 if (data->body == NULL) {
1515 str = str_new(mail->mail.data_pool, 128);
1516 if (index_mail_write_bodystructure(mail, str, FALSE) < 0)
1517 return -1;
1518 data->body = str_c(str);
1519 }
1520 break;
1521 case MAIL_CACHE_IMAP_BODYSTRUCTURE:
1522 if (data->bodystructure == NULL) {
1523 str = str_new(mail->mail.data_pool, 128);
1524 if (index_mail_write_bodystructure(mail, str, TRUE) < 0)
1525 return -1;
1526 data->bodystructure = str_c(str);
1527 }
1528 break;
1529 case MAIL_CACHE_BODY_SNIPPET:
1530 if (data->body_snippet == NULL) {
1531 if (index_mail_write_body_snippet(mail) < 0)
1532 return -1;
1533
1534 if (index_mail_want_cache(mail, MAIL_CACHE_BODY_SNIPPET))
1535 index_mail_cache_add(mail, MAIL_CACHE_BODY_SNIPPET,
1536 mail->data.body_snippet,
1537 strlen(mail->data.body_snippet));
1538 }
1539 i_assert(data->body_snippet != NULL &&
1540 data->body_snippet[0] != '\0');
1541 break;
1542 default:
1543 i_unreached();
1544 }
1545 return 0;
1546 }
1547
1548 static void
index_mail_get_plain_bodystructure(struct index_mail * mail,string_t * str,bool extended)1549 index_mail_get_plain_bodystructure(struct index_mail *mail, string_t *str,
1550 bool extended)
1551 {
1552 str_printfa(str, IMAP_BODY_PLAIN_7BIT_ASCII" %"PRIuUOFF_T" %u",
1553 mail->data.parts->body_size.virtual_size,
1554 mail->data.parts->body_size.lines);
1555 if (extended)
1556 str_append(str, " NIL NIL NIL NIL");
1557 }
1558
1559 static int
index_mail_fetch_body_snippet(struct index_mail * mail,const char ** value_r)1560 index_mail_fetch_body_snippet(struct index_mail *mail, const char **value_r)
1561 {
1562 const struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
1563 const unsigned int cache_field =
1564 cache_fields[MAIL_CACHE_BODY_SNIPPET].idx;
1565 string_t *str;
1566
1567 mail->data.cache_fetch_fields |= MAIL_FETCH_BODY_SNIPPET;
1568 if (mail->data.body_snippet == NULL) {
1569 str = str_new(mail->mail.data_pool, 128);
1570 if (index_mail_cache_lookup_field(mail, str, cache_field) > 0 &&
1571 str_len(str) > 0)
1572 mail->data.body_snippet = str_c(str);
1573 }
1574 if (mail->data.body_snippet != NULL) {
1575 *value_r = mail->data.body_snippet;
1576 return 0;
1577 }
1578
1579 /* reuse the IMAP bodystructure parsing code to get all the useful
1580 headers that we need. */
1581 mail->data.save_body_snippet = TRUE;
1582 if (index_mail_parse_bodystructure(mail, MAIL_CACHE_BODY_SNIPPET) < 0)
1583 return -1;
1584 i_assert(mail->data.body_snippet != NULL);
1585 *value_r = mail->data.body_snippet;
1586 return 0;
1587 }
1588
index_mail_get_cached_body(struct index_mail * mail,const char ** value_r)1589 bool index_mail_get_cached_body(struct index_mail *mail, const char **value_r)
1590 {
1591 const struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
1592 const unsigned int body_cache_field =
1593 cache_fields[MAIL_CACHE_IMAP_BODY].idx;
1594 const unsigned int bodystructure_cache_field =
1595 cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;
1596 struct index_mail_data *data = &mail->data;
1597 string_t *str;
1598 const char *error;
1599
1600 if (data->body != NULL) {
1601 *value_r = data->body;
1602 return TRUE;
1603 }
1604
1605 str = str_new(mail->mail.data_pool, 128);
1606 if ((data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 &&
1607 get_cached_parts(mail)) {
1608 index_mail_get_plain_bodystructure(mail, str, FALSE);
1609 *value_r = data->body = str_c(str);
1610 return TRUE;
1611 }
1612
1613 /* 2) get BODY if it exists */
1614 if (index_mail_cache_lookup_field(mail, str, body_cache_field) > 0) {
1615 *value_r = data->body = str_c(str);
1616 return TRUE;
1617 }
1618 /* 3) get it using BODYSTRUCTURE if it exists */
1619 if (index_mail_cache_lookup_field(mail, str, bodystructure_cache_field) > 0) {
1620 data->bodystructure =
1621 p_strdup(mail->mail.data_pool, str_c(str));
1622 str_truncate(str, 0);
1623
1624 if (imap_body_parse_from_bodystructure(data->bodystructure,
1625 str, &error) < 0) {
1626 /* broken, continue.. */
1627 mail_set_cache_corrupted(&mail->mail.mail,
1628 MAIL_FETCH_IMAP_BODYSTRUCTURE, t_strdup_printf(
1629 "Invalid BODYSTRUCTURE %s: %s",
1630 data->bodystructure, error));
1631 } else {
1632 *value_r = data->body = str_c(str);
1633 return TRUE;
1634 }
1635 }
1636
1637 str_free(&str);
1638 return FALSE;
1639 }
1640
index_mail_get_cached_bodystructure(struct index_mail * mail,const char ** value_r)1641 bool index_mail_get_cached_bodystructure(struct index_mail *mail,
1642 const char **value_r)
1643 {
1644 const struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
1645 const unsigned int bodystructure_cache_field =
1646 cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;
1647 struct index_mail_data *data = &mail->data;
1648 string_t *str;
1649
1650 if (data->bodystructure != NULL) {
1651 *value_r = data->bodystructure;
1652 return TRUE;
1653 }
1654
1655 str = str_new(mail->mail.data_pool, 128);
1656 if ((data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 &&
1657 get_cached_parts(mail))
1658 index_mail_get_plain_bodystructure(mail, str, TRUE);
1659 else if (index_mail_cache_lookup_field(mail, str,
1660 bodystructure_cache_field) <= 0) {
1661 str_free(&str);
1662 return FALSE;
1663 }
1664
1665 *value_r = data->bodystructure = str_c(str);
1666 if (index_mail_want_attachment_keywords_on_fetch(mail))
1667 index_mail_try_set_attachment_keywords(mail);
1668 return TRUE;
1669 }
1670
index_mail_get_special(struct mail * _mail,enum mail_fetch_field field,const char ** value_r)1671 int index_mail_get_special(struct mail *_mail,
1672 enum mail_fetch_field field, const char **value_r)
1673 {
1674 struct index_mail *mail = INDEX_MAIL(_mail);
1675 struct index_mail_data *data = &mail->data;
1676
1677 switch (field) {
1678 case MAIL_FETCH_IMAP_BODY:
1679 if (index_mail_get_cached_body(mail, value_r))
1680 return 0;
1681
1682 /* parse body structure, and save BODY/BODYSTRUCTURE
1683 depending on what we want cached */
1684 if (index_mail_parse_bodystructure(mail, MAIL_CACHE_IMAP_BODY) < 0)
1685 return -1;
1686 i_assert(data->body != NULL);
1687 *value_r = data->body;
1688 return 0;
1689 case MAIL_FETCH_IMAP_BODYSTRUCTURE:
1690 if (index_mail_get_cached_bodystructure(mail, value_r))
1691 return 0;
1692
1693 if (index_mail_parse_bodystructure(mail, MAIL_CACHE_IMAP_BODYSTRUCTURE) < 0)
1694 return -1;
1695 i_assert(data->bodystructure != NULL);
1696 *value_r = data->bodystructure;
1697 return 0;
1698 case MAIL_FETCH_IMAP_ENVELOPE:
1699 if (data->envelope == NULL) {
1700 if (index_mail_headers_get_envelope(mail) < 0)
1701 return -1;
1702 }
1703 *value_r = data->envelope;
1704 return 0;
1705 case MAIL_FETCH_FROM_ENVELOPE:
1706 *value_r = data->from_envelope != NULL ?
1707 data->from_envelope : "";
1708 return 0;
1709 case MAIL_FETCH_BODY_SNIPPET:
1710 return index_mail_fetch_body_snippet(mail, value_r);
1711 case MAIL_FETCH_STORAGE_ID:
1712 case MAIL_FETCH_UIDL_BACKEND:
1713 case MAIL_FETCH_SEARCH_RELEVANCY:
1714 case MAIL_FETCH_GUID:
1715 case MAIL_FETCH_HEADER_MD5:
1716 case MAIL_FETCH_POP3_ORDER:
1717 case MAIL_FETCH_REFCOUNT:
1718 case MAIL_FETCH_REFCOUNT_ID:
1719 *value_r = "";
1720 return 0;
1721 case MAIL_FETCH_MAILBOX_NAME:
1722 *value_r = _mail->box->vname;
1723 return 0;
1724 default:
1725 i_unreached();
1726 }
1727 }
1728
index_mail_get_backend_mail(struct mail * mail,struct mail ** real_mail_r)1729 int index_mail_get_backend_mail(struct mail *mail,
1730 struct mail **real_mail_r)
1731 {
1732 *real_mail_r = mail;
1733 return 0;
1734 }
1735
1736 struct mail *
index_mail_alloc(struct mailbox_transaction_context * t,enum mail_fetch_field wanted_fields,struct mailbox_header_lookup_ctx * wanted_headers)1737 index_mail_alloc(struct mailbox_transaction_context *t,
1738 enum mail_fetch_field wanted_fields,
1739 struct mailbox_header_lookup_ctx *wanted_headers)
1740 {
1741 struct index_mail *mail;
1742 pool_t pool;
1743
1744 pool = pool_alloconly_create("mail", 2048);
1745 mail = p_new(pool, struct index_mail, 1);
1746
1747 index_mail_init(mail, t, wanted_fields, wanted_headers, pool, NULL);
1748 return &mail->mail.mail;
1749 }
1750
index_mail_init_event(struct mail * mail)1751 static void index_mail_init_event(struct mail *mail)
1752 {
1753 mail->event = event_create(mail->box->event);
1754 event_add_category(mail->event, &event_category_mail);
1755 }
1756
index_mail_init(struct index_mail * mail,struct mailbox_transaction_context * t,enum mail_fetch_field wanted_fields,struct mailbox_header_lookup_ctx * wanted_headers,struct pool * mail_pool,struct pool * data_pool)1757 void index_mail_init(struct index_mail *mail,
1758 struct mailbox_transaction_context *t,
1759 enum mail_fetch_field wanted_fields,
1760 struct mailbox_header_lookup_ctx *wanted_headers,
1761 struct pool *mail_pool,
1762 struct pool *data_pool)
1763 {
1764 mail->mail.pool = mail_pool;
1765 array_create(&mail->mail.module_contexts, mail->mail.pool,
1766 sizeof(void *), 5);
1767
1768 mail->mail.v = *t->box->mail_vfuncs;
1769 mail->mail.mail.box = t->box;
1770 mail->mail.mail.transaction = t;
1771 index_mail_init_event(&mail->mail.mail);
1772 t->mail_ref_count++;
1773 if (data_pool != NULL)
1774 mail->mail.data_pool = data_pool;
1775 else
1776 mail->mail.data_pool = pool_alloconly_create("index_mail", 16384);
1777 mail->ibox = INDEX_STORAGE_CONTEXT(t->box);
1778 mail->mail.wanted_fields = wanted_fields;
1779 if (wanted_headers != NULL) {
1780 mail->mail.wanted_headers = wanted_headers;
1781 mailbox_header_lookup_ref(wanted_headers);
1782 }
1783 index_mail_init_data(mail);
1784 }
1785
index_mail_close_streams_full(struct index_mail * mail,bool closing)1786 static void index_mail_close_streams_full(struct index_mail *mail, bool closing)
1787 {
1788 struct index_mail_data *data = &mail->data;
1789 struct message_part *parts;
1790 const char *error;
1791
1792 if (data->parser_ctx != NULL) {
1793 if (message_parser_deinit_from_parts(&data->parser_ctx, &parts, &error) < 0)
1794 index_mail_set_message_parts_corrupted(&mail->mail.mail, error);
1795 mail->data.parser_input = NULL;
1796 if (mail->data.save_bodystructure_body)
1797 mail->data.save_bodystructure_header = TRUE;
1798 }
1799 i_stream_unref(&data->filter_stream);
1800 if (data->stream != NULL) {
1801 struct istream *orig_stream = data->stream;
1802
1803 data->destroying_stream = TRUE;
1804 if (!closing && data->destroy_callback_set) {
1805 /* we're replacing the stream with a new one. it's
1806 allowed to have references until the mail is closed
1807 (but we can't really check that) */
1808 i_stream_remove_destroy_callback(data->stream,
1809 index_mail_stream_destroy_callback);
1810 }
1811 i_stream_unref(&data->stream);
1812 /* there must be no references to the mail when the
1813 mail is being closed. */
1814 if (!closing)
1815 data->destroying_stream = FALSE;
1816 else if (mail->data.destroying_stream) {
1817 i_panic("Input stream %s unexpectedly has references",
1818 i_stream_get_name(orig_stream));
1819 }
1820
1821 data->initialized_wrapper_stream = FALSE;
1822 data->destroy_callback_set = FALSE;
1823 }
1824 }
1825
index_mail_close_streams(struct index_mail * mail)1826 void index_mail_close_streams(struct index_mail *mail)
1827 {
1828 index_mail_close_streams_full(mail, FALSE);
1829 }
1830
index_mail_init_data(struct index_mail * mail)1831 static void index_mail_init_data(struct index_mail *mail)
1832 {
1833 struct index_mail_data *data = &mail->data;
1834
1835 data->virtual_size = UOFF_T_MAX;
1836 data->physical_size = UOFF_T_MAX;
1837 data->save_date = (time_t)-1;
1838 data->received_date = (time_t)-1;
1839 data->sent_date.time = (uint32_t)-1;
1840 data->dont_cache_field_idx = UINT_MAX;
1841
1842 data->wanted_fields = mail->mail.wanted_fields;
1843 if (mail->mail.wanted_headers != NULL) {
1844 data->wanted_headers = mail->mail.wanted_headers;
1845 mailbox_header_lookup_ref(data->wanted_headers);
1846 }
1847 }
1848
index_mail_reset_data(struct index_mail * mail)1849 static void index_mail_reset_data(struct index_mail *mail)
1850 {
1851 i_zero(&mail->data);
1852 p_clear(mail->mail.data_pool);
1853
1854 index_mail_init_data(mail);
1855
1856 mail->mail.mail.seq = 0;
1857 mail->mail.mail.uid = 0;
1858 mail->mail.seq_pvt = 0;
1859 mail->mail.mail.expunged = FALSE;
1860 mail->mail.mail.has_nuls = FALSE;
1861 mail->mail.mail.has_no_nuls = FALSE;
1862 mail->mail.mail.saving = FALSE;
1863 mail->mail.mail.mail_stream_opened = FALSE;
1864 mail->mail.mail.mail_metadata_accessed = FALSE;
1865 }
1866
index_mail_close(struct mail * _mail)1867 void index_mail_close(struct mail *_mail)
1868 {
1869 struct index_mail *mail = INDEX_MAIL(_mail);
1870
1871 if (mail->mail.mail.seq == 0) {
1872 /* mail_set_seq*() hasn't been called yet, or is being called
1873 right now. Don't reset anything yet. We especially don't
1874 want to reset wanted_fields or wanted_headers so that
1875 mail_add_temp_wanted_fields() can be called by plugins
1876 before mail_set_seq_saving() for
1877 mail_save_context.dest_mail. */
1878 return;
1879 }
1880
1881 /* make sure old mail isn't visible in the event anymore even if it's
1882 attempted to be used. */
1883 event_unref(&_mail->event);
1884
1885 /* If uid == 0 but seq != 0, we came here from saving a (non-mbox)
1886 message. If that happens, don't bother checking if anything should
1887 be cached since it was already checked. Also by now the transaction
1888 may have already been rollbacked and seq point to a nonexistent
1889 message. */
1890 if (mail->mail.mail.uid != 0) {
1891 index_mail_cache_sizes(mail);
1892 index_mail_cache_dates(mail);
1893 }
1894
1895 index_mail_close_streams_full(mail, TRUE);
1896 /* Notify cache that the mail is no longer open. This mainly helps
1897 with INDEX=MEMORY to keep all data added with mail_cache_add() in
1898 memory until this point. */
1899 mail_cache_close_mail(_mail->transaction->cache_trans, _mail->seq);
1900
1901 mailbox_header_lookup_unref(&mail->data.wanted_headers);
1902 if (!mail->freeing)
1903 index_mail_reset_data(mail);
1904 }
1905
check_envelope(struct index_mail * mail)1906 static void check_envelope(struct index_mail *mail)
1907 {
1908 struct mail *_mail = &mail->mail.mail;
1909 const unsigned int cache_field_envelope =
1910 mail->ibox->cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx;
1911 unsigned int cache_field_hdr;
1912
1913 if ((mail->data.access_part & PARSE_HDR) != 0) {
1914 mail->data.save_envelope = TRUE;
1915 return;
1916 }
1917
1918 /* if "imap.envelope" is cached, that's all we need */
1919 if (mail_cache_field_exists(_mail->transaction->cache_view,
1920 _mail->seq, cache_field_envelope) > 0)
1921 return;
1922
1923 /* don't waste time doing full checks for all required
1924 headers. assume that if we have "hdr.message-id" cached,
1925 we don't need to parse the header. */
1926 cache_field_hdr = mail_cache_register_lookup(_mail->box->cache,
1927 "hdr.message-id");
1928 if (cache_field_hdr == UINT_MAX ||
1929 mail_cache_field_exists(_mail->transaction->cache_view,
1930 _mail->seq, cache_field_hdr) <= 0)
1931 mail->data.access_part |= PARSE_HDR;
1932 mail->data.save_envelope = TRUE;
1933 }
1934
index_mail_update_access_parts_pre(struct mail * _mail)1935 void index_mail_update_access_parts_pre(struct mail *_mail)
1936 {
1937 struct index_mail *mail = INDEX_MAIL(_mail);
1938 struct index_mail_data *data = &mail->data;
1939 struct mail_storage *storage = _mail->box->storage;
1940 const struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
1941 struct mail_cache_view *cache_view = _mail->transaction->cache_view;
1942 const struct mail_storage_settings *mail_set = _mail->box->storage->set;
1943
1944 if (_mail->seq == 0) {
1945 /* mail_add_temp_wanted_fields() called before mail_set_seq*().
1946 We'll allow this, since it can be useful for plugins to
1947 call it for mail_save_context.dest_mail. This function
1948 is called again in mail_set_seq*(). */
1949 return;
1950 }
1951
1952 if ((data->wanted_fields & (MAIL_FETCH_NUL_STATE |
1953 MAIL_FETCH_IMAP_BODY |
1954 MAIL_FETCH_IMAP_BODYSTRUCTURE)) != 0 &&
1955 !_mail->has_nuls && !_mail->has_no_nuls) {
1956 (void)index_mail_get_fixed_field(mail, MAIL_CACHE_FLAGS,
1957 &data->cache_flags,
1958 sizeof(data->cache_flags));
1959 _mail->has_nuls =
1960 (data->cache_flags & MAIL_CACHE_FLAG_HAS_NULS) != 0;
1961 _mail->has_no_nuls =
1962 (data->cache_flags & MAIL_CACHE_FLAG_HAS_NO_NULS) != 0;
1963 /* we currently don't forcibly set the nul state. if it's not
1964 already cached, the caller can figure out itself what to
1965 do when neither is set */
1966 }
1967
1968 /* see if wanted_fields can tell us if we need to read/parse
1969 header/body */
1970 if ((data->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0 &&
1971 (storage->nonbody_access_fields & MAIL_FETCH_MESSAGE_PARTS) == 0 &&
1972 data->parts == NULL) {
1973 const unsigned int cache_field =
1974 cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx;
1975
1976 if (mail_cache_field_exists(cache_view, _mail->seq,
1977 cache_field) <= 0) {
1978 data->access_part |= PARSE_HDR | PARSE_BODY;
1979 data->save_message_parts = TRUE;
1980 }
1981 }
1982
1983 if ((data->wanted_fields & MAIL_FETCH_IMAP_ENVELOPE) != 0 &&
1984 (storage->nonbody_access_fields & MAIL_FETCH_IMAP_ENVELOPE) == 0 &&
1985 data->envelope == NULL)
1986 check_envelope(mail);
1987
1988 if ((data->wanted_fields & MAIL_FETCH_IMAP_BODY) != 0 &&
1989 (data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) == 0 &&
1990 (storage->nonbody_access_fields & MAIL_FETCH_IMAP_BODY) == 0 &&
1991 data->body == NULL) {
1992 /* we need either imap.body or imap.bodystructure */
1993 const unsigned int cache_field1 =
1994 cache_fields[MAIL_CACHE_IMAP_BODY].idx;
1995 const unsigned int cache_field2 =
1996 cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;
1997
1998 if (mail_cache_field_exists(cache_view, _mail->seq,
1999 cache_field1) <= 0 &&
2000 mail_cache_field_exists(cache_view, _mail->seq,
2001 cache_field2) <= 0) {
2002 data->access_part |= PARSE_HDR | PARSE_BODY;
2003 data->save_bodystructure_header = TRUE;
2004 data->save_bodystructure_body = TRUE;
2005 }
2006 }
2007
2008 if ((data->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0 &&
2009 (data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) == 0 &&
2010 (storage->nonbody_access_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) == 0 &&
2011 data->bodystructure == NULL) {
2012 const unsigned int cache_field =
2013 cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;
2014
2015 if (mail_cache_field_exists(cache_view, _mail->seq,
2016 cache_field) <= 0) {
2017 data->access_part |= PARSE_HDR | PARSE_BODY;
2018 data->save_bodystructure_header = TRUE;
2019 data->save_bodystructure_body = TRUE;
2020 }
2021 }
2022
2023 if ((data->wanted_fields & MAIL_FETCH_DATE) != 0 &&
2024 (storage->nonbody_access_fields & MAIL_FETCH_DATE) == 0 &&
2025 data->sent_date.time == (uint32_t)-1) {
2026 const unsigned int cache_field =
2027 cache_fields[MAIL_CACHE_SENT_DATE].idx;
2028
2029 if (mail_cache_field_exists(cache_view, _mail->seq,
2030 cache_field) <= 0) {
2031 data->access_part |= PARSE_HDR;
2032 data->save_sent_date = TRUE;
2033 }
2034 }
2035 if ((data->wanted_fields & MAIL_FETCH_BODY_SNIPPET) != 0 &&
2036 (storage->nonbody_access_fields & MAIL_FETCH_BODY_SNIPPET) == 0) {
2037 const unsigned int cache_field =
2038 cache_fields[MAIL_CACHE_BODY_SNIPPET].idx;
2039
2040 if (mail_cache_field_exists(cache_view, _mail->seq,
2041 cache_field) <= 0) {
2042 data->access_part |= PARSE_HDR | PARSE_BODY;
2043 data->save_body_snippet = TRUE;
2044 }
2045 }
2046 if ((data->wanted_fields & (MAIL_FETCH_STREAM_HEADER |
2047 MAIL_FETCH_STREAM_BODY)) != 0) {
2048 if ((data->wanted_fields & MAIL_FETCH_STREAM_HEADER) != 0)
2049 data->access_part |= READ_HDR;
2050 if ((data->wanted_fields & MAIL_FETCH_STREAM_BODY) != 0)
2051 data->access_part |= READ_BODY;
2052 }
2053
2054 /* NOTE: Keep this attachment detection the last, so that the
2055 access_part check works correctly.
2056
2057 The attachment flag detection is done while parsing BODYSTRUCTURE.
2058 We want to do this for mails that are being saved, but also when
2059 we need to open the mail body anyway. */
2060 if (mail_set->parsed_mail_attachment_detection_add_flags &&
2061 (_mail->saving || data->access_part != 0) &&
2062 !mail_has_attachment_keywords(&mail->mail.mail)) {
2063 data->save_bodystructure_header = TRUE;
2064 data->save_bodystructure_body = TRUE;
2065 }
2066 }
2067
index_mail_update_access_parts_post(struct mail * _mail)2068 void index_mail_update_access_parts_post(struct mail *_mail)
2069 {
2070 struct index_mail *mail = INDEX_MAIL(_mail);
2071 struct index_mail_data *data = &mail->data;
2072 const struct mail_index_header *hdr;
2073 struct istream *input;
2074
2075 if (_mail->seq == 0) {
2076 /* see index_mail_update_access_parts_pre() */
2077 return;
2078 }
2079
2080 /* when mail_prefetch_count>1, at this point we've started the
2081 prefetching to all the mails and we're now starting to access the
2082 first mail. */
2083
2084 if (data->access_part != 0) {
2085 /* open stream immediately to set expunged flag if
2086 it's already lost */
2087
2088 /* open the stream only if we didn't get here from
2089 mailbox_save_init() */
2090 hdr = mail_index_get_header(_mail->transaction->view);
2091 if (!_mail->saving && _mail->uid < hdr->next_uid) {
2092 if ((data->access_part & (READ_BODY | PARSE_BODY)) != 0)
2093 (void)mail_get_stream_because(_mail, NULL, NULL, "access", &input);
2094 else
2095 (void)mail_get_hdr_stream(_mail, NULL, &input);
2096 }
2097 }
2098 }
2099
index_mail_get_age_days(struct mail * mail,int * days_r)2100 static bool index_mail_get_age_days(struct mail *mail, int *days_r)
2101 {
2102 int age_days;
2103 const struct mail_index_header *hdr =
2104 mail_index_get_header(mail->transaction->view);
2105 int n_days = N_ELEMENTS(hdr->day_first_uid);
2106
2107 for (age_days = 0; age_days < n_days; age_days++) {
2108 if (mail->uid >= hdr->day_first_uid[age_days])
2109 break;
2110 }
2111
2112 if (age_days == n_days) {
2113 /* mail is too old, cannot determine its age from
2114 day_first_uid[]. */
2115 return FALSE;
2116 }
2117
2118 if (hdr->day_stamp != 0) {
2119 /* offset for hdr->day_stamp */
2120 age_days += (ioloop_time - hdr->day_stamp) / (3600 * 24);
2121 }
2122 *days_r = age_days;
2123 return TRUE;
2124 }
2125
index_mail_set_seq(struct mail * _mail,uint32_t seq,bool saving)2126 void index_mail_set_seq(struct mail *_mail, uint32_t seq, bool saving)
2127 {
2128 struct index_mail *mail = INDEX_MAIL(_mail);
2129 int age_days;
2130
2131 if (mail->data.seq == seq) {
2132 if (!saving)
2133 return;
2134 /* we started saving a mail, aborted it, and now we're saving
2135 another mail with the same sequence. make sure the mail
2136 gets reset. */
2137 }
2138
2139 mail->mail.v.close(&mail->mail.mail);
2140
2141 mail->data.seq = seq;
2142 mail->mail.mail.seq = seq;
2143 mail->mail.mail.saving = saving;
2144 mail_index_lookup_uid(_mail->transaction->view, seq,
2145 &mail->mail.mail.uid);
2146
2147 /* Recreate the mail event when changing mails. Even though the same
2148 mail struct is reused, they are practically different mails. */
2149 event_unref(&_mail->event);
2150 index_mail_init_event(_mail);
2151 event_add_int(_mail->event, "seq", _mail->seq);
2152 event_add_int(_mail->event, "uid", _mail->uid);
2153 /* Add mail age field to event. */
2154 if (index_mail_get_age_days(_mail, &age_days))
2155 event_add_int(_mail->event, "mail_age_days", age_days);
2156
2157 event_set_append_log_prefix(_mail->event, t_strdup_printf(
2158 "%sUID %u: ", saving ? "saving " : "", _mail->uid));
2159
2160 if (mail_index_view_is_inconsistent(_mail->transaction->view)) {
2161 mail_set_expunged(&mail->mail.mail);
2162 return;
2163 }
2164 /* Allow callers to easily find out if this mail was already expunged
2165 by another session. It's possible that it could still be
2166 successfully accessed. */
2167 if (mail_index_is_expunged(_mail->transaction->view, seq))
2168 mail_set_expunged(&mail->mail.mail);
2169
2170 if (!mail->mail.search_mail) {
2171 index_mail_update_access_parts_pre(_mail);
2172 index_mail_update_access_parts_post(_mail);
2173 } else {
2174 /* searching code will call the
2175 index_mail_update_access_parts_*() after we know the mail is
2176 actually wanted to be fetched. */
2177 }
2178 mail->data.initialized = TRUE;
2179 }
2180
index_mail_prefetch(struct mail * _mail)2181 bool index_mail_prefetch(struct mail *_mail)
2182 {
2183 struct index_mail *mail = INDEX_MAIL(_mail);
2184 /* HAVE_POSIX_FADVISE alone isn't enough for CentOS 4.9 */
2185 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
2186 struct mail_storage *storage = _mail->box->storage;
2187 struct istream *input;
2188 off_t len;
2189 int fd;
2190
2191 if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_FILE_PER_MSG) == 0) {
2192 /* we're handling only file-per-msg storages for now. */
2193 return TRUE;
2194 }
2195 if (mail->data.access_part == 0) {
2196 /* everything we need is cached */
2197 return TRUE;
2198 }
2199
2200 if (mail->data.stream == NULL) {
2201 (void)mail_get_stream_because(_mail, NULL, NULL, "prefetch", &input);
2202 if (mail->data.stream == NULL)
2203 return TRUE;
2204 }
2205
2206 /* tell OS to start reading the file into memory */
2207 fd = i_stream_get_fd(mail->data.stream);
2208 if (fd != -1) {
2209 if ((mail->data.access_part & (READ_BODY | PARSE_BODY)) != 0)
2210 len = 0;
2211 else
2212 len = MAIL_READ_HDR_BLOCK_SIZE;
2213 if (posix_fadvise(fd, 0, len, POSIX_FADV_WILLNEED) < 0) {
2214 i_error("posix_fadvise(%s) failed: %m",
2215 i_stream_get_name(mail->data.stream));
2216 }
2217 mail->data.prefetch_sent = TRUE;
2218 }
2219 #endif
2220 return !mail->data.prefetch_sent;
2221 }
2222
index_mail_set_uid(struct mail * _mail,uint32_t uid)2223 bool index_mail_set_uid(struct mail *_mail, uint32_t uid)
2224 {
2225 struct index_mail *mail = INDEX_MAIL(_mail);
2226 uint32_t seq;
2227
2228 if (mail_index_lookup_seq(_mail->transaction->view, uid, &seq)) {
2229 index_mail_set_seq(_mail, seq, FALSE);
2230 return TRUE;
2231 } else {
2232 mail->mail.v.close(&mail->mail.mail);
2233 mail->mail.mail.uid = uid;
2234 mail_set_expunged(&mail->mail.mail);
2235 return FALSE;
2236 }
2237 }
2238
index_mail_add_temp_wanted_fields(struct mail * _mail,enum mail_fetch_field fields,struct mailbox_header_lookup_ctx * headers)2239 void index_mail_add_temp_wanted_fields(struct mail *_mail,
2240 enum mail_fetch_field fields,
2241 struct mailbox_header_lookup_ctx *headers)
2242 {
2243 struct index_mail *mail = INDEX_MAIL(_mail);
2244 struct index_mail_data *data = &mail->data;
2245 struct mailbox_header_lookup_ctx *new_wanted_headers;
2246
2247 data->wanted_fields |= fields;
2248 if (headers == NULL) {
2249 /* keep old ones */
2250 } else if (data->wanted_headers == NULL) {
2251 data->wanted_headers = headers;
2252 mailbox_header_lookup_ref(headers);
2253 } else {
2254 /* merge headers */
2255 new_wanted_headers = mailbox_header_lookup_merge(data->wanted_headers,
2256 headers);
2257 mailbox_header_lookup_unref(&data->wanted_headers);
2258 data->wanted_headers = new_wanted_headers;
2259 }
2260 index_mail_update_access_parts_pre(_mail);
2261 /* Don't call _post(), which would try to open the stream. It should be
2262 enough to delay the opening until it happens anyway.
2263
2264 Otherwise there's not really any good place to call this in the
2265 plugins: set_seq() call get_stream() internally, which can already
2266 start parsing the headers, so it's too late. If we use get_stream()
2267 and there's a _post() call here, it gets into infinite loop. The
2268 loop could probably be prevented in some way, but it's probably
2269 better to eventually try to remove the _post() call entirely
2270 everywhere. */
2271 }
2272
index_mail_set_uid_cache_updates(struct mail * _mail,bool set)2273 void index_mail_set_uid_cache_updates(struct mail *_mail, bool set)
2274 {
2275 struct index_mail *mail = INDEX_MAIL(_mail);
2276
2277 mail->data.no_caching = set || mail->data.forced_no_caching;
2278 }
2279
index_mail_free(struct mail * _mail)2280 void index_mail_free(struct mail *_mail)
2281 {
2282 struct index_mail *mail = INDEX_MAIL(_mail);
2283
2284 mail->freeing = TRUE;
2285 mail->mail.v.close(_mail);
2286
2287 i_assert(_mail->transaction->mail_ref_count > 0);
2288 _mail->transaction->mail_ref_count--;
2289
2290 buffer_free(&mail->header_data);
2291 if (array_is_created(&mail->header_lines))
2292 array_free(&mail->header_lines);
2293 if (array_is_created(&mail->header_match))
2294 array_free(&mail->header_match);
2295 if (array_is_created(&mail->header_match_lines))
2296 array_free(&mail->header_match_lines);
2297
2298 mailbox_header_lookup_unref(&mail->data.wanted_headers);
2299 mailbox_header_lookup_unref(&mail->mail.wanted_headers);
2300 event_unref(&_mail->event);
2301 pool_unref(&mail->mail.data_pool);
2302 pool_unref(&mail->mail.pool);
2303 }
2304
index_mail_cache_parse_continue(struct mail * _mail)2305 void index_mail_cache_parse_continue(struct mail *_mail)
2306 {
2307 struct index_mail *mail = INDEX_MAIL(_mail);
2308 struct message_block block;
2309
2310 while (message_parser_parse_next_block(mail->data.parser_ctx,
2311 &block) > 0) {
2312 if (block.size != 0)
2313 continue;
2314
2315 if (!mail->data.header_parsed) {
2316 index_mail_parse_header(block.part, block.hdr, mail);
2317 if (block.hdr == NULL)
2318 mail->data.header_parsed = TRUE;
2319 } else {
2320 message_part_data_parse_from_header(mail->mail.data_pool,
2321 block.part, block.hdr);
2322 }
2323 }
2324 }
2325
index_mail_cache_parse_deinit(struct mail * _mail,time_t received_date,bool success)2326 void index_mail_cache_parse_deinit(struct mail *_mail, time_t received_date,
2327 bool success)
2328 {
2329 struct index_mail *mail = INDEX_MAIL(_mail);
2330
2331 if (!success) {
2332 /* we're going to delete this mail anyway,
2333 don't bother trying to update cache file */
2334 mail->data.no_caching = TRUE;
2335 mail->data.forced_no_caching = TRUE;
2336
2337 if (mail->data.parser_ctx == NULL) {
2338 /* we didn't even start cache parsing */
2339 i_assert(!mail->data.header_parser_initialized);
2340 return;
2341 }
2342 }
2343
2344 /* This is needed with 0 byte mails to get hdr=NULL call done. */
2345 index_mail_cache_parse_continue(_mail);
2346
2347 if (mail->data.received_date == (time_t)-1)
2348 mail->data.received_date = received_date;
2349 if (mail->data.save_date == (time_t)-1) {
2350 /* this save_date may not be exactly the same as what we get
2351 in future, but then again neither mbox nor maildir
2352 guarantees it anyway. */
2353 mail->data.save_date = ioloop_time;
2354 }
2355
2356 (void)index_mail_parse_body_finish(mail, 0, success);
2357 }
2358
2359 static bool
index_mail_update_pvt_flags(struct mail * _mail,enum modify_type modify_type,enum mail_flags pvt_flags)2360 index_mail_update_pvt_flags(struct mail *_mail, enum modify_type modify_type,
2361 enum mail_flags pvt_flags)
2362 {
2363 struct mail_private *mail = (struct mail_private *)_mail;
2364 const struct mail_index_record *rec;
2365 enum mail_flags old_pvt_flags;
2366
2367 if (!index_mail_get_pvt(_mail))
2368 return FALSE;
2369 if (pvt_flags == 0 && modify_type != MODIFY_REPLACE)
2370 return FALSE;
2371
2372 /* see if the flags actually change anything */
2373 rec = mail_index_lookup(_mail->transaction->view_pvt, mail->seq_pvt);
2374 old_pvt_flags = rec->flags & mailbox_get_private_flags_mask(_mail->box);
2375
2376 switch (modify_type) {
2377 case MODIFY_ADD:
2378 return (old_pvt_flags & pvt_flags) != pvt_flags;
2379 case MODIFY_REPLACE:
2380 return old_pvt_flags != pvt_flags;
2381 case MODIFY_REMOVE:
2382 return (old_pvt_flags & pvt_flags) != 0;
2383 }
2384 i_unreached();
2385 }
2386
index_mail_update_flags(struct mail * _mail,enum modify_type modify_type,enum mail_flags flags)2387 void index_mail_update_flags(struct mail *_mail, enum modify_type modify_type,
2388 enum mail_flags flags)
2389 {
2390 struct mail_private *mail = (struct mail_private *)_mail;
2391 enum mail_flags pvt_flags_mask, pvt_flags = 0;
2392 bool update_modseq = FALSE;
2393
2394 flags &= MAIL_FLAGS_NONRECENT | MAIL_INDEX_MAIL_FLAG_BACKEND;
2395
2396 if (_mail->box->view_pvt != NULL) {
2397 /* mailbox has private flags */
2398 pvt_flags_mask = mailbox_get_private_flags_mask(_mail->box);
2399 pvt_flags = flags & pvt_flags_mask;
2400 flags &= ENUM_NEGATE(pvt_flags_mask);
2401 if (index_mail_update_pvt_flags(_mail, modify_type, pvt_flags)) {
2402 mail_index_update_flags(_mail->transaction->itrans_pvt,
2403 mail->seq_pvt,
2404 modify_type, pvt_flags);
2405 update_modseq = TRUE;
2406 }
2407 }
2408
2409 if (!update_modseq) {
2410 /* no forced modseq update */
2411 } else if (modify_type == MODIFY_REMOVE) {
2412 /* add the modseq update separately */
2413 mail_index_update_flags(_mail->transaction->itrans, _mail->seq,
2414 MODIFY_ADD, (enum mail_flags )MAIL_INDEX_MAIL_FLAG_UPDATE_MODSEQ);
2415 } else {
2416 /* add as part of the flag updates */
2417 flags |= MAIL_INDEX_MAIL_FLAG_UPDATE_MODSEQ;
2418 }
2419 mail_index_update_flags(_mail->transaction->itrans, _mail->seq,
2420 modify_type, flags);
2421 }
2422
index_mail_update_keywords(struct mail * mail,enum modify_type modify_type,struct mail_keywords * keywords)2423 void index_mail_update_keywords(struct mail *mail, enum modify_type modify_type,
2424 struct mail_keywords *keywords)
2425 {
2426 struct index_mail *imail = INDEX_MAIL(mail);
2427
2428 if (array_is_created(&imail->data.keyword_indexes))
2429 array_free(&imail->data.keyword_indexes);
2430 if (array_is_created(&imail->data.keywords)) {
2431 /* clear the keywords array so the next mail_get_keywords()
2432 returns the updated keywords. don't free the array, because
2433 then any existing mail_get_keywords() return values would
2434 point to broken data. this won't leak memory because the
2435 array is allocated from mail's memory pool. */
2436 memset(&imail->data.keywords, 0,
2437 sizeof(imail->data.keywords));
2438 }
2439
2440 mail_index_update_keywords(mail->transaction->itrans, mail->seq,
2441 modify_type, keywords);
2442 }
2443
index_mail_update_modseq(struct mail * mail,uint64_t min_modseq)2444 void index_mail_update_modseq(struct mail *mail, uint64_t min_modseq)
2445 {
2446 mail_index_update_modseq(mail->transaction->itrans, mail->seq,
2447 min_modseq);
2448 }
2449
index_mail_update_pvt_modseq(struct mail * mail,uint64_t min_pvt_modseq)2450 void index_mail_update_pvt_modseq(struct mail *mail, uint64_t min_pvt_modseq)
2451 {
2452 if (mail->box->view_pvt == NULL)
2453 return;
2454 index_transaction_init_pvt(mail->transaction);
2455 mail_index_update_modseq(mail->transaction->itrans_pvt, mail->seq,
2456 min_pvt_modseq);
2457 }
2458
index_mail_expunge(struct mail * mail)2459 void index_mail_expunge(struct mail *mail)
2460 {
2461 enum mail_lookup_abort old_abort = mail->lookup_abort;
2462 const char *value;
2463 guid_128_t guid_128;
2464
2465 mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
2466 if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
2467 mail_index_expunge(mail->transaction->itrans, mail->seq);
2468 else {
2469 mail_generate_guid_128_hash(value, guid_128);
2470 mail_index_expunge_guid(mail->transaction->itrans,
2471 mail->seq, guid_128);
2472 }
2473 mail->lookup_abort = old_abort;
2474 }
2475
index_mail_parse(struct mail * mail,bool parse_body)2476 static void index_mail_parse(struct mail *mail, bool parse_body)
2477 {
2478 struct index_mail *imail = INDEX_MAIL(mail);
2479
2480 imail->data.access_part |= PARSE_HDR;
2481 if (index_mail_parse_headers(imail, NULL, "precache") == 0) {
2482 if (parse_body) {
2483 imail->data.access_part |= PARSE_BODY;
2484 (void)index_mail_parse_body(imail, 0);
2485 }
2486 }
2487 }
2488
index_mail_precache(struct mail * mail)2489 int index_mail_precache(struct mail *mail)
2490 {
2491 struct index_mail *imail = INDEX_MAIL(mail);
2492 enum mail_fetch_field cache;
2493 time_t date;
2494 uoff_t size;
2495 const char *str;
2496
2497 if (mail_cache_field_exists_any(mail->transaction->cache_view,
2498 mail->seq)) {
2499 /* already cached this mail (we should get here only if FTS
2500 plugin decreased the first precached seq) */
2501 return 0;
2502 }
2503
2504 cache = imail->data.wanted_fields;
2505 if ((cache & (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
2506 index_mail_parse(mail, (cache & MAIL_FETCH_STREAM_BODY) != 0);
2507 if ((cache & MAIL_FETCH_RECEIVED_DATE) != 0)
2508 (void)mail_get_received_date(mail, &date);
2509 if ((cache & MAIL_FETCH_SAVE_DATE) != 0)
2510 (void)mail_get_save_date(mail, &date);
2511 if ((cache & MAIL_FETCH_VIRTUAL_SIZE) != 0)
2512 (void)mail_get_virtual_size(mail, &size);
2513 if ((cache & MAIL_FETCH_PHYSICAL_SIZE) != 0)
2514 (void)mail_get_physical_size(mail, &size);
2515 if ((cache & MAIL_FETCH_UIDL_BACKEND) != 0)
2516 (void)mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &str);
2517 if ((cache & MAIL_FETCH_POP3_ORDER) != 0)
2518 (void)mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str);
2519 if ((cache & MAIL_FETCH_GUID) != 0)
2520 (void)mail_get_special(mail, MAIL_FETCH_GUID, &str);
2521 return 0;
2522 }
2523
2524 static void
index_mail_reset_vsize_ext(struct mail * mail)2525 index_mail_reset_vsize_ext(struct mail *mail)
2526 {
2527 unsigned int idx;
2528 uint32_t vsize = 0;
2529 struct mail_index_view *view = mail->transaction->view;
2530 if (mail_index_map_get_ext_idx(view->map, mail->box->mail_vsize_ext_id,
2531 &idx)) {
2532 mail_index_update_ext(mail->transaction->itrans, mail->seq,
2533 mail->box->mail_vsize_ext_id, &vsize, NULL);
2534 }
2535 }
2536
index_mail_set_cache_corrupted(struct mail * mail,enum mail_fetch_field field,const char * reason)2537 void index_mail_set_cache_corrupted(struct mail *mail,
2538 enum mail_fetch_field field,
2539 const char *reason)
2540 {
2541 struct index_mail *imail = INDEX_MAIL(mail);
2542 const char *field_name;
2543
2544 switch ((int)field) {
2545 case 0:
2546 field_name = "fields";
2547 break;
2548 case MAIL_FETCH_PHYSICAL_SIZE:
2549 field_name = "physical size";
2550 imail->data.physical_size = UOFF_T_MAX;
2551 imail->data.virtual_size = UOFF_T_MAX;
2552 imail->data.parts = NULL;
2553 index_mail_reset_vsize_ext(mail);
2554 break;
2555 case MAIL_FETCH_VIRTUAL_SIZE:
2556 field_name = "virtual size";
2557 imail->data.physical_size = UOFF_T_MAX;
2558 imail->data.virtual_size = UOFF_T_MAX;
2559 imail->data.parts = NULL;
2560 index_mail_reset_vsize_ext(mail);
2561 break;
2562 case MAIL_FETCH_MESSAGE_PARTS:
2563 field_name = "MIME parts";
2564 imail->data.parts = NULL;
2565 break;
2566 case MAIL_FETCH_IMAP_BODY:
2567 field_name = "IMAP BODY";
2568 imail->data.body = NULL;
2569 imail->data.bodystructure = NULL;
2570 break;
2571 case MAIL_FETCH_IMAP_BODYSTRUCTURE:
2572 field_name = "IMAP BODYSTRUCTURE";
2573 imail->data.body = NULL;
2574 imail->data.bodystructure = NULL;
2575 break;
2576 default:
2577 field_name = t_strdup_printf("#%x", field);
2578 }
2579
2580 /* make sure we don't cache invalid values */
2581 mail_cache_transaction_reset(mail->transaction->cache_trans);
2582 imail->data.no_caching = TRUE;
2583 imail->data.forced_no_caching = TRUE;
2584
2585 if (mail->saving) {
2586 mail_set_critical(mail,
2587 "BUG: Broken %s found while saving a new mail: %s",
2588 field_name, reason);
2589 } else if (reason[0] == '\0') {
2590 mail_set_mail_cache_corrupted(mail,
2591 "Broken %s in mailbox %s",
2592 field_name, mail->box->vname);
2593 } else {
2594 mail_set_mail_cache_corrupted(mail,
2595 "Broken %s in mailbox %s: %s",
2596 field_name, mail->box->vname, reason);
2597 }
2598 }
2599
index_mail_opened(struct mail * mail,struct istream ** stream ATTR_UNUSED)2600 int index_mail_opened(struct mail *mail,
2601 struct istream **stream ATTR_UNUSED)
2602 {
2603 mail_opened_event(mail);
2604 return 0;
2605 }
2606
index_mail_save_finish(struct mail_save_context * ctx)2607 void index_mail_save_finish(struct mail_save_context *ctx)
2608 {
2609 struct index_mail *imail = INDEX_MAIL(ctx->dest_mail);
2610
2611 index_mail_save_finish_make_snippet(imail);
2612
2613 if (ctx->data.from_envelope != NULL &&
2614 imail->data.from_envelope == NULL) {
2615 imail->data.from_envelope =
2616 p_strdup(imail->mail.data_pool, ctx->data.from_envelope);
2617 }
2618 }
2619
index_mail_cache_reason(struct mail * mail,const char * reason)2620 const char *index_mail_cache_reason(struct mail *mail, const char *reason)
2621 {
2622 const char *cache_reason =
2623 mail_cache_get_missing_reason(mail->transaction->cache_view, mail->seq);
2624 return t_strdup_printf("%s (%s)", reason, cache_reason);
2625 }
2626