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