index-mail-headers.c revision 9db263f2b9ab771fbf9a2bff44a245c45eaef218
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "lib.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "istream.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "buffer.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "str.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "message-date.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "message-parser.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "istream-header-filter.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "imap-envelope.h"
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen#include "imap-bodystructure.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "index-storage.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "index-mail.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include <stdlib.h>
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct index_header_lookup_ctx {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mailbox_header_lookup_ctx ctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pool_t pool;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size_t count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int *idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char **name;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen};
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int header_line_cmp(const void *p1, const void *p2)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct index_mail_line *l1 = p1, *l2 = p2;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int diff;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen diff = (int)l1->field_idx - (int)l2->field_idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return diff != 0 ? diff :
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (int)l1->line_num - (int)l2->line_num;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void index_mail_parse_header_finish(struct index_mail *mail)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen static uint32_t null = 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail_line *lines;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const unsigned char *header, *data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const uint8_t *match;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_t *buf;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size_t i, j, size, data_size, match_idx, match_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int noncontiguous;
8fb1e3e2349c9940732b5bb77a2a4053b8f72a4fTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_push();
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines = buffer_get_modifyable_data(mail->header_lines, &size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size /= sizeof(*lines);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* sort it first so fields are grouped together and ordered by
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen line number */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen qsort(lines, size, sizeof(*lines), header_line_cmp);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen match = buffer_get_data(mail->header_match, &match_size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header = buffer_get_data(mail->header_data, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = match_idx = 0; i < size; i = j) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen while (match_idx < lines[i].field_idx &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen match_idx < match_size) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (match[match_idx] == mail->header_match_value) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* this header doesn't exist. remember that. */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_write(mail->header_offsets,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen match_idx * sizeof(null),
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen &null, sizeof(null));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_add(mail->trans->cache_trans,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->data.seq, match_idx,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen NULL, 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen match_idx++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen match_idx++;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_set_used_size(buf, 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, &lines[i].line_num,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sizeof(lines[i].line_num));
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen noncontiguous = FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (j = i+1; j < size; j++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (lines[j].field_idx != lines[i].field_idx)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (lines[j].start_pos != lines[j-1].end_pos)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen noncontiguous = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, &lines[j].line_num,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sizeof(lines[j].line_num));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, &null, sizeof(uint32_t));
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (noncontiguous) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (; i < j; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, header + lines[i].start_pos,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines[i].end_pos -
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines[i].start_pos);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i--;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, header + lines[i].start_pos,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines[j-1].end_pos - lines[i].start_pos);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data = buffer_get_data(buf, &data_size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_add(mail->trans->cache_trans, mail->data.seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines[i].field_idx, data, data_size);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen for (; match_idx < match_size; match_idx++) {
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen if (match[match_idx] == mail->header_match_value) {
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen /* this header doesn't exist. remember that. */
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen mail_cache_add(mail->trans->cache_trans,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen mail->data.seq, match_idx, NULL, 0);
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen }
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen }
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid index_mail_parse_header_init(struct index_mail *mail,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mailbox_header_lookup_ctx *_headers)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_header_lookup_ctx *headers =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (struct index_header_lookup_ctx *)_headers;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size_t i;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen mail->header_seq = mail->data.seq;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail->header_data == NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->header_data =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_create_dynamic(default_pool, 4096, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->header_lines =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_create_dynamic(default_pool, 256, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->header_match =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_create_dynamic(default_pool, 64, (size_t)-1);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen mail->header_offsets =
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_create_dynamic(default_pool, 256, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_set_used_size(mail->header_data, 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_set_used_size(mail->header_lines, 0);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_set_used_size(mail->header_offsets, 0);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen mail->header_match_value += 2;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (mail->header_match_value == 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* wrapped, we'll have to clear the buffer */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memset(buffer_get_modifyable_data(mail->header_match, NULL), 0,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_get_size(mail->header_match));
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen mail->header_match_value = 2;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (headers != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < headers->count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_write(mail->header_match, headers->idx[i],
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen &mail->header_match_value, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail->wanted_headers != NULL && mail->wanted_headers != headers) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen headers = mail->wanted_headers;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < headers->count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_write(mail->header_match, headers->idx[i],
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen &mail->header_match_value, 1);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void index_mail_parse_finish_imap_envelope(struct index_mail *mail)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen string_t *str;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str = str_new(mail->pool, 256);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_envelope_write_part_data(mail->data.envelope_data, str);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->data.envelope = str_c(str);
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_add(mail->trans->cache_trans, mail->data.seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen MAIL_CACHE_ENVELOPE, str_data(str), str_len(str));
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainenint index_mail_parse_header(struct message_part *part,
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen struct message_header_line *hdr,
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen struct index_mail *mail)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen struct index_mail_data *data = &mail->data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen enum mail_cache_decision_type decision;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *cache_field_name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field_idx;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen int timezone, first_hdr = FALSE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line_num++;
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (data->save_bodystructure_header) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(part != NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_bodystructure_parse_header(mail->pool, part, hdr);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (data->save_envelope) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen imap_envelope_parse_header(mail->pool,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen &data->envelope_data, hdr);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (hdr == NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen index_mail_parse_finish_imap_envelope(mail);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (hdr == NULL) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* end of headers */
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (data->save_sent_date) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* not found */
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen data->sent_date.time = 0;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen data->sent_date.timezone = 0;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen data->save_sent_date = FALSE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (data->sent_date.time != (time_t)-1) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen mail_cache_add(mail->trans->cache_trans, data->seq,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen MAIL_CACHE_SENT_DATE, &data->sent_date,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen sizeof(data->sent_date));
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen index_mail_parse_header_finish(mail);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->save_bodystructure_header = FALSE;
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen return TRUE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (data->save_sent_date && strcasecmp(hdr->name, "Date") == 0) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (hdr->continues)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen hdr->use_full_value = TRUE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen else {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (!message_date_parse(hdr->full_value,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen hdr->full_value_len,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen &data->sent_date.time,
bb8937e0c503b49a752858f00445646062b6f06eTimo Sirainen &timezone)) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* 0 == parse error */
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen data->sent_date.time = 0;
bb8937e0c503b49a752858f00445646062b6f06eTimo Sirainen timezone = 0;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
bb8937e0c503b49a752858f00445646062b6f06eTimo Sirainen data->sent_date.timezone = timezone;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen data->save_sent_date = FALSE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!hdr->continued) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_push();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cache_field_name = t_strconcat("hdr.", hdr->name, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.field_idx =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_register_lookup(mail->ibox->cache,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cache_field_name);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen field_idx = data->parse_line.field_idx;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (field_idx == (unsigned int)-1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we don't want this field */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!hdr->continued) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen decision = mail_cache_field_get_decision(mail->ibox->cache,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen field_idx);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.cache =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (decision & ~MAIL_CACHE_DECISION_FORCED) !=
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen MAIL_CACHE_DECISION_NO;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (data->parse_line.cache &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_field_exists(mail->trans->cache_view,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->seq, field_idx) > 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* already cached */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.cache = FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!data->parse_line.cache) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen uint8_t *match;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size_t size;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen match = buffer_get_modifyable_data(mail->header_match, &size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (field_idx >= size ||
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen (match[field_idx] & ~1) != mail->header_match_value) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we don't need to do anything with this header */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return TRUE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (match[field_idx] == mail->header_match_value) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* first header */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen first_hdr = TRUE;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen match[field_idx]++;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!hdr->continued) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.start_pos = str_len(mail->header_data);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.line_num = data->parse_line_num;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append(mail->header_data, hdr->name);
60576cd64e6a537413cd90104f7e862f71d48c81Timo Sirainen str_append_n(mail->header_data, hdr->middle, hdr->middle_len);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (first_hdr) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* save the offset to first header */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen uint32_t pos = str_len(mail->header_data);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_write(mail->header_offsets,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen field_idx * sizeof(pos),
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen &pos, sizeof(pos));
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen }
203560029e3ad8687c2c759e6a81ecdb8b37ebe6Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append_n(mail->header_data, hdr->value, hdr->value_len);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!hdr->no_newline)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append(mail->header_data, "\n");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!hdr->continues) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.end_pos = str_len(mail->header_data);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(mail->header_lines, &data->parse_line,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sizeof(data->parse_line));
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen return TRUE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenindex_mail_parse_header_cb(struct message_part *part,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct message_header_line *hdr, void *context)
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = context;
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)index_mail_parse_header(part, hdr, mail);
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainen}
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainen
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainenint index_mail_parse_headers(struct index_mail *mail,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen struct mailbox_header_lookup_ctx *headers)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen struct index_mail_data *data = &mail->data;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen return -1;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen index_mail_parse_header_init(mail, headers);
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (data->parts == NULL && data->parser_ctx == NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* initialize bodystructure parsing in case we read the whole
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen message. */
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen data->parser_ctx =
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen message_parser_init(mail->pool, data->stream);
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen message_parser_parse_header(data->parser_ctx, &data->hdr_size,
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen index_mail_parse_header_cb, mail);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* just read the header */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen message_parse_header(data->parts, data->stream, &data->hdr_size,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen index_mail_parse_header_cb, mail);
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen }
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen data->hdr_size_set = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_header = FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenimap_envelope_parse_callback(struct message_part *part __attr_unused__,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct message_header_line *hdr, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = context;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_envelope_parse_header(mail->pool, &mail->data.envelope_data, hdr);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (hdr == NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen index_mail_parse_finish_imap_envelope(mail);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid index_mail_headers_get_envelope(struct index_mail *mail)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mailbox_header_lookup_ctx *header_ctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct istream *stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
36977c4a74e164f7d81eb4785f0a5d3ff436fd19Timo Sirainen mail->data.save_envelope = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header_ctx = mailbox_header_lookup_init(&mail->ibox->box,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_envelope_headers);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream = mail->mail.get_headers(&mail->mail, header_ctx);
9db263f2b9ab771fbf9a2bff44a245c45eaef218Timo Sirainen if (mail->data.envelope == NULL && stream != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we got the headers from cache - parse them to get the
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen envelope */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen message_parse_header(NULL, stream, NULL,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_envelope_parse_callback, mail);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->data.save_envelope = FALSE;
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mailbox_header_lookup_deinit(header_ctx);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic unsigned int
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenget_header_field_idx(struct index_mailbox *ibox, const char *field)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache_field header_field = {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen NULL, 0, MAIL_CACHE_FIELD_HEADER, 0,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen MAIL_CACHE_DECISION_TEMP
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen };
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *cache_field_name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field_idx;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_push();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cache_field_name = t_strconcat("hdr.", field, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen field_idx = mail_cache_register_lookup(ibox->cache, cache_field_name);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (field_idx == (unsigned int)-1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header_field.name = cache_field_name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_register_fields(ibox->cache, &header_field, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen field_idx = header_field.idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return field_idx;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic size_t get_header_size(buffer_t *buffer, size_t pos)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen{
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen const unsigned char *data;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen size_t i, size;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen data = buffer_get_data(buffer, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen i_assert(pos <= size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen for (i = pos; i < size; i++) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (data[i] == '\n') {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (i+1 == size ||
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen (data[i+1] != ' ' && data[i+1] != '\t'))
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return i - pos;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen }
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen }
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return size - pos;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen}
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic int index_mail_header_is_parsed(struct index_mail *mail,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen unsigned int field_idx)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen{
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen const uint8_t *match;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen size_t size;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen match = buffer_get_data(mail->header_match, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (field_idx >= size)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return -1;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (match[field_idx] == mail->header_match_value)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return 0;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen else if (match[field_idx] == mail->header_match_value + 1)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return 1;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return -1;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen}
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic const char *
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenindex_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen{
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen const unsigned char *data;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen const uint32_t *offsets;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen size_t size;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen offsets = buffer_get_data(mail->header_offsets, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen i_assert(field_idx * sizeof(*offsets) >= size &&
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen offsets[field_idx] != 0);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen data = buffer_get_data(mail->header_data, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen size = get_header_size(mail->header_data, offsets[field_idx]);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return p_strndup(mail->pool, data + offsets[field_idx], size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen}
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenconst char *index_mail_get_header(struct mail *_mail, const char *field)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen const char *headers[2];
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const unsigned char *data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field_idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen string_t *dest;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen size_t i, len;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int ret;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen field_idx = get_header_field_idx(mail->ibox, field);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen dest = str_new(mail->pool, 128);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->data.seq, &field_idx, 1) <= 0) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* not in cache / error - first see if it's already parsed */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen p_free(mail->pool, dest);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (mail->header_seq == mail->data.seq) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen ret = index_mail_header_is_parsed(mail, field_idx);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (ret != -1) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return ret == 0 ? NULL :
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen index_mail_get_parsed_header(mail,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen field_idx);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen }
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen }
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* parse */
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen headers[0] = field; headers[1] = NULL;
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen headers_ctx = mailbox_header_lookup_init(&mail->ibox->box,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen headers);
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen ret = index_mail_parse_headers(mail, headers_ctx);
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen mailbox_header_lookup_deinit(headers_ctx);
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen if (ret < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return NULL;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen ret = index_mail_header_is_parsed(mail, field_idx);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen i_assert(ret != -1);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return ret == 0 ? NULL :
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen index_mail_get_parsed_header(mail, field_idx);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
8f61542ca70f3f0dda15630447a00877b132efa8Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* cached. skip "header name: " in dest. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data = str_data(dest);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen len = str_len(dest);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < len; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (data[i] == ':') {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (i+1 != len && data[++i] == ' ') i++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* return only the first field in case there's multiple. */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen len = get_header_size(dest, i);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_set_used_size(dest, i + len);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen return str_c(dest) + i;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void header_cache_callback(struct message_header_line *hdr,
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen int *matched, void *context)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = context;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen if (hdr != NULL && hdr->eoh)
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen *matched = FALSE;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)index_mail_parse_header(NULL, hdr, mail);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct istream *
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenindex_mail_get_headers(struct mail *_mail,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mailbox_header_lookup_ctx *_headers)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_header_lookup_ctx *headers =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (struct index_header_lookup_ctx *)_headers;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen string_t *dest;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen if (mail->data.save_bodystructure_header) {
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen /* we have to parse the header. */
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen if (index_mail_parse_headers(mail, _headers) < 0)
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen return NULL;
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen }
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen dest = str_new(mail->pool, 256);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->data.seq, headers->idx,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen headers->count) > 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return i_stream_create_from_data(mail->pool,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_data(dest), str_len(dest));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* not in cache / error */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen p_free(mail->pool, dest);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen return NULL;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail->data.filter_stream != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_stream_unref(mail->data.filter_stream);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen index_mail_parse_header_init(mail, _headers);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail->data.filter_stream =
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen i_stream_create_header_filter(mail->data.stream,
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen HEADER_FILTER_INCLUDE |
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen HEADER_FILTER_HIDE_BODY,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen headers->name, headers->count,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header_cache_callback, mail);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return mail->data.filter_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct mailbox_header_lookup_ctx *
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenindex_header_lookup_init(struct mailbox *box, const char *const headers[])
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mailbox *ibox = (struct index_mailbox *)box;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache_field *fields, header_field = {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen NULL, 0, MAIL_CACHE_FIELD_HEADER, 0,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen MAIL_CACHE_DECISION_TEMP
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen };
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_header_lookup_ctx *ctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *const *name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char **sorted_headers;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_t *buf;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pool_t pool;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size_t i, size;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (size = 0, name = headers; *name != NULL; name++)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size++;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_push();
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (size > 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* headers need to be sorted for filter stream. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sorted_headers = t_new(const char *, size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memcpy(sorted_headers, headers, size * sizeof(*sorted_headers));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen qsort(sorted_headers, size, sizeof(*sorted_headers),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen strcasecmp_p);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen headers = sorted_headers;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 128, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < size; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header_field.name = t_strconcat("hdr.", headers[i], NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, &header_field, sizeof(header_field));
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen fields = buffer_get_modifyable_data(buf, &size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size /= sizeof(*fields);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_register_fields(ibox->cache, fields, size);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pool = pool_alloconly_create("index_header_lookup_ctx", 256);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx = p_new(pool, struct index_header_lookup_ctx, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->ctx.box = box;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->pool = pool;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->count = size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (size > 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->idx = p_new(pool, unsigned int, size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->name = p_new(pool, const char *, size);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* @UNSAFE */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < size; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx->idx[i] = fields[i].idx;
d6a1fe8633cf50cdf9441a7f4c2171bbd562ca9bTimo Sirainen ctx->name[i] = p_strdup(pool, headers[i]);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return &ctx->ctx;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid index_header_lookup_deinit(struct mailbox_header_lookup_ctx *_ctx)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_header_lookup_ctx *ctx =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (struct index_header_lookup_ctx *)_ctx;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pool_unref(ctx->pool);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}