1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "ioloop.h"
5 #include "buffer.h"
6 #include "hash.h"
7 #include "hex-binary.h"
8 #include "crc32.h"
9 #include "sha1.h"
10 #include "hostpid.h"
11 #include "istream.h"
12 #include "mail-cache.h"
13 #include "mail-storage-private.h"
14 #include "message-id.h"
15 #include "message-part-data.h"
16 #include "imap-bodystructure.h"
17
18 #include <time.h>
19
mail_alloc(struct mailbox_transaction_context * t,enum mail_fetch_field wanted_fields,struct mailbox_header_lookup_ctx * wanted_headers)20 struct mail *mail_alloc(struct mailbox_transaction_context *t,
21 enum mail_fetch_field wanted_fields,
22 struct mailbox_header_lookup_ctx *wanted_headers)
23 {
24 struct mail *mail;
25
26 i_assert(wanted_headers == NULL || wanted_headers->box == t->box);
27
28 T_BEGIN {
29 mail = t->box->v.mail_alloc(t, wanted_fields, wanted_headers);
30 hook_mail_allocated(mail);
31 } T_END;
32
33 return mail;
34 }
35
mail_free(struct mail ** mail)36 void mail_free(struct mail **mail)
37 {
38 struct mail_private *p = (struct mail_private *)*mail;
39
40 /* make sure mailbox_search_*() users don't try to free the mail
41 directly */
42 i_assert(!p->search_mail);
43
44 p->v.free(*mail);
45 *mail = NULL;
46 }
47
mail_set_seq(struct mail * mail,uint32_t seq)48 void mail_set_seq(struct mail *mail, uint32_t seq)
49 {
50 struct mail_private *p = (struct mail_private *)mail;
51
52 T_BEGIN {
53 p->v.set_seq(mail, seq, FALSE);
54 } T_END;
55 }
56
mail_set_seq_saving(struct mail * mail,uint32_t seq)57 void mail_set_seq_saving(struct mail *mail, uint32_t seq)
58 {
59 struct mail_private *p = (struct mail_private *)mail;
60
61 T_BEGIN {
62 p->v.set_seq(mail, seq, TRUE);
63 } T_END;
64 }
65
mail_set_uid(struct mail * mail,uint32_t uid)66 bool mail_set_uid(struct mail *mail, uint32_t uid)
67 {
68 struct mail_private *p = (struct mail_private *)mail;
69 bool ret;
70
71 T_BEGIN {
72 ret = p->v.set_uid(mail, uid);
73 } T_END;
74 return ret;
75 }
76
mail_prefetch(struct mail * mail)77 bool mail_prefetch(struct mail *mail)
78 {
79 struct mail_private *p = (struct mail_private *)mail;
80 bool ret;
81
82 T_BEGIN {
83 ret = p->v.prefetch(mail);
84 } T_END;
85 return ret;
86 }
87
mail_add_temp_wanted_fields(struct mail * mail,enum mail_fetch_field fields,struct mailbox_header_lookup_ctx * headers)88 void mail_add_temp_wanted_fields(struct mail *mail,
89 enum mail_fetch_field fields,
90 struct mailbox_header_lookup_ctx *headers)
91 {
92 struct mail_private *p = (struct mail_private *)mail;
93
94 i_assert(headers == NULL || headers->box == mail->box);
95
96 p->v.add_temp_wanted_fields(mail, fields, headers);
97 }
98
mail_get_flags(struct mail * mail)99 enum mail_flags mail_get_flags(struct mail *mail)
100 {
101 struct mail_private *p = (struct mail_private *)mail;
102
103 return p->v.get_flags(mail);
104 }
105
mail_get_modseq(struct mail * mail)106 uint64_t mail_get_modseq(struct mail *mail)
107 {
108 struct mail_private *p = (struct mail_private *)mail;
109
110 return p->v.get_modseq(mail);
111 }
112
mail_get_pvt_modseq(struct mail * mail)113 uint64_t mail_get_pvt_modseq(struct mail *mail)
114 {
115 struct mail_private *p = (struct mail_private *)mail;
116
117 return p->v.get_pvt_modseq(mail);
118 }
119
mail_get_keywords(struct mail * mail)120 const char *const *mail_get_keywords(struct mail *mail)
121 {
122 struct mail_private *p = (struct mail_private *)mail;
123
124 return p->v.get_keywords(mail);
125 }
126
ARRAY_TYPE(keyword_indexes)127 const ARRAY_TYPE(keyword_indexes) *mail_get_keyword_indexes(struct mail *mail)
128 {
129 struct mail_private *p = (struct mail_private *)mail;
130
131 return p->v.get_keyword_indexes(mail);
132 }
133
mail_get_parts(struct mail * mail,struct message_part ** parts_r)134 int mail_get_parts(struct mail *mail, struct message_part **parts_r)
135 {
136 struct mail_private *p = (struct mail_private *)mail;
137 int ret;
138
139 T_BEGIN {
140 ret = p->v.get_parts(mail, parts_r);
141 } T_END;
142 return ret;
143 }
144
mail_get_date(struct mail * mail,time_t * date_r,int * timezone_r)145 int mail_get_date(struct mail *mail, time_t *date_r, int *timezone_r)
146 {
147 struct mail_private *p = (struct mail_private *)mail;
148 int ret;
149
150 T_BEGIN {
151 ret = p->v.get_date(mail, date_r, timezone_r);
152 } T_END;
153 return ret;
154 }
155
mail_get_received_date(struct mail * mail,time_t * date_r)156 int mail_get_received_date(struct mail *mail, time_t *date_r)
157 {
158 struct mail_private *p = (struct mail_private *)mail;
159 int ret;
160
161 T_BEGIN {
162 ret = p->v.get_received_date(mail, date_r);
163 } T_END;
164 return ret;
165 }
166
mail_get_save_date(struct mail * mail,time_t * date_r)167 int mail_get_save_date(struct mail *mail, time_t *date_r)
168 {
169 struct mail_private *p = (struct mail_private *)mail;
170 int ret;
171
172 T_BEGIN {
173 ret = p->v.get_save_date(mail, date_r);
174 } T_END;
175 return ret;
176 }
177
mail_get_virtual_size(struct mail * mail,uoff_t * size_r)178 int mail_get_virtual_size(struct mail *mail, uoff_t *size_r)
179 {
180 struct mail_private *p = (struct mail_private *)mail;
181 int ret;
182
183 T_BEGIN {
184 ret = p->v.get_virtual_size(mail, size_r);
185 } T_END;
186 return ret;
187 }
188
mail_get_physical_size(struct mail * mail,uoff_t * size_r)189 int mail_get_physical_size(struct mail *mail, uoff_t *size_r)
190 {
191 struct mail_private *p = (struct mail_private *)mail;
192 int ret;
193
194 T_BEGIN {
195 ret = p->v.get_physical_size(mail, size_r);
196 } T_END;
197 return ret;
198 }
199
mail_get_first_header(struct mail * mail,const char * field,const char ** value_r)200 int mail_get_first_header(struct mail *mail, const char *field,
201 const char **value_r)
202 {
203 struct mail_private *p = (struct mail_private *)mail;
204 int ret;
205
206 T_BEGIN {
207 ret = p->v.get_first_header(mail, field, FALSE, value_r);
208 } T_END;
209 return ret;
210 }
211
mail_get_first_header_utf8(struct mail * mail,const char * field,const char ** value_r)212 int mail_get_first_header_utf8(struct mail *mail, const char *field,
213 const char **value_r)
214 {
215 struct mail_private *p = (struct mail_private *)mail;
216 int ret;
217
218 T_BEGIN {
219 ret = p->v.get_first_header(mail, field, TRUE, value_r);
220 } T_END;
221 return ret;
222 }
223
mail_get_headers(struct mail * mail,const char * field,const char * const ** value_r)224 int mail_get_headers(struct mail *mail, const char *field,
225 const char *const **value_r)
226 {
227 struct mail_private *p = (struct mail_private *)mail;
228 int ret;
229
230 T_BEGIN {
231 ret = p->v.get_headers(mail, field, FALSE, value_r);
232 } T_END;
233 return ret;
234 }
235
mail_get_headers_utf8(struct mail * mail,const char * field,const char * const ** value_r)236 int mail_get_headers_utf8(struct mail *mail, const char *field,
237 const char *const **value_r)
238 {
239 struct mail_private *p = (struct mail_private *)mail;
240 int ret;
241
242 T_BEGIN {
243 ret = p->v.get_headers(mail, field, TRUE, value_r);
244 } T_END;
245 return ret;
246 }
247
mail_get_header_stream(struct mail * mail,struct mailbox_header_lookup_ctx * headers,struct istream ** stream_r)248 int mail_get_header_stream(struct mail *mail,
249 struct mailbox_header_lookup_ctx *headers,
250 struct istream **stream_r)
251 {
252 struct mail_private *p = (struct mail_private *)mail;
253 int ret;
254
255 i_assert(headers->count > 0);
256 i_assert(headers->box == mail->box);
257
258 T_BEGIN {
259 ret = p->v.get_header_stream(mail, headers, stream_r);
260 } T_END;
261 return ret;
262 }
263
mail_set_aborted(struct mail * mail)264 void mail_set_aborted(struct mail *mail)
265 {
266 mail_storage_set_error(mail->box->storage, MAIL_ERROR_LOOKUP_ABORTED,
267 "Mail field not cached");
268 }
269
mail_get_stream(struct mail * mail,struct message_size * hdr_size,struct message_size * body_size,struct istream ** stream_r)270 int mail_get_stream(struct mail *mail, struct message_size *hdr_size,
271 struct message_size *body_size, struct istream **stream_r)
272 {
273 return mail_get_stream_because(mail, hdr_size, body_size,
274 "mail stream", stream_r);
275 }
276
mail_get_stream_because(struct mail * mail,struct message_size * hdr_size,struct message_size * body_size,const char * reason,struct istream ** stream_r)277 int mail_get_stream_because(struct mail *mail, struct message_size *hdr_size,
278 struct message_size *body_size,
279 const char *reason, struct istream **stream_r)
280 {
281 struct mail_private *p = (struct mail_private *)mail;
282 int ret;
283
284 if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
285 mail_set_aborted(mail);
286 return -1;
287 }
288 T_BEGIN {
289 p->get_stream_reason = reason;
290 ret = p->v.get_stream(mail, TRUE, hdr_size, body_size, stream_r);
291 p->get_stream_reason = "";
292 } T_END;
293 i_assert(ret < 0 || (*stream_r)->blocking);
294 return ret;
295 }
296
mail_get_hdr_stream(struct mail * mail,struct message_size * hdr_size,struct istream ** stream_r)297 int mail_get_hdr_stream(struct mail *mail, struct message_size *hdr_size,
298 struct istream **stream_r)
299 {
300 return mail_get_hdr_stream_because(mail, hdr_size, "header stream", stream_r);
301 }
302
mail_get_hdr_stream_because(struct mail * mail,struct message_size * hdr_size,const char * reason,struct istream ** stream_r)303 int mail_get_hdr_stream_because(struct mail *mail,
304 struct message_size *hdr_size,
305 const char *reason, struct istream **stream_r)
306 {
307 struct mail_private *p = (struct mail_private *)mail;
308 int ret;
309
310 if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
311 mail_set_aborted(mail);
312 return -1;
313 }
314 T_BEGIN {
315 p->get_stream_reason = reason;
316 ret = p->v.get_stream(mail, FALSE, hdr_size, NULL, stream_r);
317 p->get_stream_reason = "";
318 } T_END;
319 i_assert(ret < 0 || (*stream_r)->blocking);
320 return ret;
321 }
322
mail_get_binary_stream(struct mail * mail,const struct message_part * part,bool include_hdr,uoff_t * size_r,bool * binary_r,struct istream ** stream_r)323 int mail_get_binary_stream(struct mail *mail, const struct message_part *part,
324 bool include_hdr, uoff_t *size_r,
325 bool *binary_r, struct istream **stream_r)
326 {
327 struct mail_private *p = (struct mail_private *)mail;
328 int ret;
329
330 if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
331 mail_set_aborted(mail);
332 return -1;
333 }
334 T_BEGIN {
335 ret = p->v.get_binary_stream(mail, part, include_hdr,
336 size_r, NULL, binary_r, stream_r);
337 } T_END;
338 i_assert(ret < 0 || (*stream_r)->blocking);
339 return ret;
340 }
341
mail_get_binary_size(struct mail * mail,const struct message_part * part,bool include_hdr,uoff_t * size_r,unsigned int * lines_r)342 int mail_get_binary_size(struct mail *mail, const struct message_part *part,
343 bool include_hdr, uoff_t *size_r,
344 unsigned int *lines_r)
345 {
346 struct mail_private *p = (struct mail_private *)mail;
347 bool binary;
348 int ret;
349
350 T_BEGIN {
351 ret = p->v.get_binary_stream(mail, part, include_hdr,
352 size_r, lines_r, &binary, NULL);
353 } T_END;
354 return ret;
355 }
356
mail_get_special(struct mail * mail,enum mail_fetch_field field,const char ** value_r)357 int mail_get_special(struct mail *mail, enum mail_fetch_field field,
358 const char **value_r)
359 {
360 struct mail_private *p = (struct mail_private *)mail;
361
362 if (p->v.get_special(mail, field, value_r) < 0)
363 return -1;
364 i_assert(*value_r != NULL);
365 return 0;
366 }
367
mail_get_backend_mail(struct mail * mail,struct mail ** real_mail_r)368 int mail_get_backend_mail(struct mail *mail, struct mail **real_mail_r)
369 {
370 struct mail_private *p = (struct mail_private *)mail;
371 return p->v.get_backend_mail(mail, real_mail_r);
372 }
373
mail_get_message_id(struct mail * mail,const char ** value_r)374 int mail_get_message_id(struct mail *mail, const char **value_r)
375 {
376 const char *hdr_value, *msgid_bare;
377 int ret;
378
379 *value_r = NULL;
380
381 ret = mail_get_first_header(mail, "Message-ID", &hdr_value);
382 if (ret <= 0)
383 return ret;
384
385 msgid_bare = message_id_get_next(&hdr_value);
386 if (msgid_bare == NULL)
387 return 0;
388
389 /* Complete the message ID with surrounding `<' and `>'. */
390 *value_r = t_strconcat("<", msgid_bare, ">", NULL);
391 return 1;
392 }
393
mail_update_flags(struct mail * mail,enum modify_type modify_type,enum mail_flags flags)394 void mail_update_flags(struct mail *mail, enum modify_type modify_type,
395 enum mail_flags flags)
396 {
397 struct mail_private *p = (struct mail_private *)mail;
398
399 p->v.update_flags(mail, modify_type, flags);
400 }
401
mail_update_keywords(struct mail * mail,enum modify_type modify_type,struct mail_keywords * keywords)402 void mail_update_keywords(struct mail *mail, enum modify_type modify_type,
403 struct mail_keywords *keywords)
404 {
405 struct mail_private *p = (struct mail_private *)mail;
406
407 p->v.update_keywords(mail, modify_type, keywords);
408 }
409
mail_update_modseq(struct mail * mail,uint64_t min_modseq)410 void mail_update_modseq(struct mail *mail, uint64_t min_modseq)
411 {
412 struct mail_private *p = (struct mail_private *)mail;
413
414 p->v.update_modseq(mail, min_modseq);
415 }
416
mail_update_pvt_modseq(struct mail * mail,uint64_t min_pvt_modseq)417 void mail_update_pvt_modseq(struct mail *mail, uint64_t min_pvt_modseq)
418 {
419 struct mail_private *p = (struct mail_private *)mail;
420
421 p->v.update_pvt_modseq(mail, min_pvt_modseq);
422 }
423
mail_update_pop3_uidl(struct mail * mail,const char * uidl)424 void mail_update_pop3_uidl(struct mail *mail, const char *uidl)
425 {
426 struct mail_private *p = (struct mail_private *)mail;
427
428 if (p->v.update_pop3_uidl != NULL)
429 p->v.update_pop3_uidl(mail, uidl);
430 }
431
mail_expunge(struct mail * mail)432 void mail_expunge(struct mail *mail)
433 {
434 struct mail_private *p = (struct mail_private *)mail;
435
436 T_BEGIN {
437 p->v.expunge(mail);
438 } T_END;
439 mail_expunge_requested_event(mail);
440 }
441
mail_autoexpunge(struct mail * mail)442 void mail_autoexpunge(struct mail *mail)
443 {
444 struct mail_private *p = (struct mail_private *)mail;
445 p->autoexpunged = TRUE;
446 mail_expunge(mail);
447 p->autoexpunged = FALSE;
448 }
449
mail_set_expunged(struct mail * mail)450 void mail_set_expunged(struct mail *mail)
451 {
452 mail_storage_set_error(mail->box->storage, MAIL_ERROR_EXPUNGED,
453 "Message was expunged");
454 mail->expunged = TRUE;
455 }
456
mail_precache(struct mail * mail)457 int mail_precache(struct mail *mail)
458 {
459 struct mail_private *p = (struct mail_private *)mail;
460 int ret;
461
462 T_BEGIN {
463 ret = p->v.precache(mail);
464 } T_END;
465 return ret;
466 }
467
mail_set_cache_corrupted(struct mail * mail,enum mail_fetch_field field,const char * reason)468 void mail_set_cache_corrupted(struct mail *mail,
469 enum mail_fetch_field field,
470 const char *reason)
471 {
472 struct mail_private *p = (struct mail_private *)mail;
473 p->v.set_cache_corrupted(mail, field, reason);
474 }
475
mail_generate_guid_128_hash(const char * guid,guid_128_t guid_128_r)476 void mail_generate_guid_128_hash(const char *guid, guid_128_t guid_128_r)
477 {
478 unsigned char sha1_sum[SHA1_RESULTLEN];
479 buffer_t buf;
480
481 if (guid_128_from_string(guid, guid_128_r) < 0) {
482 /* not 128bit hex. use a hash of it instead. */
483 buffer_create_from_data(&buf, guid_128_r, GUID_128_SIZE);
484 buffer_set_used_size(&buf, 0);
485 sha1_get_digest(guid, strlen(guid), sha1_sum);
486 #if SHA1_RESULTLEN < GUID_128_SIZE
487 # error not possible
488 #endif
489 buffer_append(&buf,
490 sha1_sum + SHA1_RESULTLEN - GUID_128_SIZE,
491 GUID_128_SIZE);
492 }
493 }
494
495 static bool
mail_message_has_attachment(struct message_part * part,const struct message_part_attachment_settings * set)496 mail_message_has_attachment(struct message_part *part,
497 const struct message_part_attachment_settings *set)
498 {
499 for (; part != NULL; part = part->next) {
500 if (message_part_is_attachment(part, set) ||
501 mail_message_has_attachment(part->children, set))
502 return TRUE;
503 }
504
505 return FALSE;
506 }
507
mail_has_attachment_keywords(struct mail * mail)508 bool mail_has_attachment_keywords(struct mail *mail)
509 {
510 const char *const *kw = mail_get_keywords(mail);
511 return (str_array_icase_find(kw, MAIL_KEYWORD_HAS_ATTACHMENT) !=
512 str_array_icase_find(kw, MAIL_KEYWORD_HAS_NO_ATTACHMENT));
513 }
514
mail_parse_parts(struct mail * mail,struct message_part ** parts_r)515 static int mail_parse_parts(struct mail *mail, struct message_part **parts_r)
516 {
517 const char *structure, *error;
518 struct mail_private *pmail = (struct mail_private*)mail;
519
520 /* need to get bodystructure first */
521 if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
522 &structure) < 0) {
523 /* Don't bother logging an error. See
524 mail_set_attachment_keywords(). */
525 return -1;
526 }
527 if (imap_bodystructure_parse_full(structure, pmail->data_pool, parts_r,
528 &error) < 0) {
529 mail_set_cache_corrupted(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
530 error);
531 return -1;
532 }
533 return 0;
534 }
535
mail_set_attachment_keywords(struct mail * mail)536 int mail_set_attachment_keywords(struct mail *mail)
537 {
538 int ret;
539 const struct mail_storage_settings *mail_set =
540 mail_storage_get_settings(mailbox_get_storage(mail->box));
541
542 const char *const keyword_has_attachment[] = {
543 MAIL_KEYWORD_HAS_ATTACHMENT,
544 NULL,
545 };
546 const char *const keyword_has_no_attachment[] = {
547 MAIL_KEYWORD_HAS_NO_ATTACHMENT,
548 NULL
549 };
550 struct message_part_attachment_settings set = {
551 .content_type_filter =
552 mail_set->parsed_mail_attachment_content_type_filter,
553 .exclude_inlined =
554 mail_set->parsed_mail_attachment_exclude_inlined,
555 };
556 struct mail_keywords *kw_has = NULL, *kw_has_not = NULL;
557
558 /* walk all parts and see if there is an attachment */
559 struct message_part *parts;
560 if (mail_get_parts(mail, &parts) < 0) {
561 /* Callers don't really care about the exact error, and
562 critical errors were already logged. Most importantly we
563 don't want to log MAIL_ERROR_LOOKUP_ABORTED since that is
564 an expected error. */
565 ret = -1;
566 } else if (parts->data == NULL &&
567 mail_parse_parts(mail, &parts) < 0) {
568 ret = -1;
569 } else if (mailbox_keywords_create(mail->box, keyword_has_attachment, &kw_has) < 0 ||
570 mailbox_keywords_create(mail->box, keyword_has_no_attachment, &kw_has_not) < 0) {
571 mail_set_critical(mail, "Failed to add attachment keywords: "
572 "mailbox_keywords_create(%s) failed: %s",
573 mailbox_get_vname(mail->box),
574 mail_storage_get_last_internal_error(mail->box->storage, NULL));
575 ret = -1;
576 } else {
577 bool has_attachment = mail_message_has_attachment(parts, &set);
578
579 /* make sure only one of the keywords gets set */
580 mail_update_keywords(mail, MODIFY_REMOVE, has_attachment ? kw_has_not : kw_has);
581 mail_update_keywords(mail, MODIFY_ADD, has_attachment ? kw_has : kw_has_not);
582 ret = has_attachment ? 1 : 0;
583 }
584
585 if (kw_has != NULL)
586 mailbox_keywords_unref(&kw_has);
587 if (kw_has_not != NULL)
588 mailbox_keywords_unref(&kw_has_not);
589
590 return ret;
591 }
592
mail_opened_event(struct mail * mail)593 void mail_opened_event(struct mail *mail)
594 {
595 struct mail_private *pmail =
596 container_of(mail, struct mail_private, mail);
597 struct event_passthrough *e = event_create_passthrough(mail->event)->
598 set_name("mail_opened")->
599 add_str("reason", pmail->get_stream_reason);
600 if (pmail->get_stream_reason != NULL)
601 e_debug(e->event(), "Opened mail because: %s",
602 pmail->get_stream_reason);
603 else
604 e_debug(e->event(), "Opened mail");
605 }
606
mail_expunge_requested_event(struct mail * mail)607 void mail_expunge_requested_event(struct mail *mail)
608 {
609 struct event_passthrough *e = event_create_passthrough(mail->event)->
610 set_name("mail_expunge_requested")->
611 add_int("uid", mail->uid)->
612 add_int("seq", mail->seq);
613 e_debug(e->event(), "Expunge requested");
614 }
615