bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainenstatic const enum message_header_parser_flags hdr_parser_flags =
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainenstatic const enum message_parser_flags msg_parser_flags =
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenstatic int header_line_cmp(const struct index_mail_line *l1,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen diff = (int)l1->field_idx - (int)l2->field_idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void index_mail_parse_header_finish(struct index_mail *mail)
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen unsigned int i, j, count, match_idx, match_count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* sort it first so fields are grouped together and ordered by
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen line number */
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&mail->header_lines, header_line_cmp);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen lines = array_get(&mail->header_lines, &count);
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen match = array_get(&mail->header_match, &match_count);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* go through all the header lines we found */
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* matches and header lines are both sorted, all matches
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen until lines[i] weren't found */
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (HEADER_MATCH_USABLE(mail, match[match_idx]) &&
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen mail_cache_field_can_add(_mail->transaction->cache_trans,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* this header doesn't exist. remember that. */
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* save index to first header line */
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen array_idx_set(&mail->header_match_lines, match_idx, &j);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (!mail_cache_field_can_add(_mail->transaction->cache_trans,
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen /* header is already cached. skip over all the
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen header lines. */
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* buffer contains: { uint32_t line_num[], 0, header texts }
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen noncontiguous is just a small optimization.. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (; i < j; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, header + lines[i].start_pos,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(buf, header + lines[i].start_pos,
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen index_mail_cache_add_idx(mail, lines[i].field_idx,
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen for (; match_idx < match_count; match_idx++) {
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (HEADER_MATCH_USABLE(mail, match[match_idx]) &&
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen mail_cache_field_can_add(_mail->transaction->cache_trans,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen /* this header doesn't exist. remember that. */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen index_mail_cache_add_idx(mail, match_idx, "", 0);
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainenstatic unsigned int
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenget_header_field_idx(struct mailbox *box, const char *field,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen header_field.name = t_strconcat("hdr.", field, NULL);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen mail_cache_register_fields(box->cache, &header_field, 1);
77af0bd168cf3e3ddc3ae68abc82bfad7e9b5ff4Timo Sirainenbool index_mail_want_parse_headers(struct index_mail *mail)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if ((mail->data.cache_fetch_fields & MAIL_FETCH_DATE) != 0 &&
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic void index_mail_parse_header_register_all_wanted(struct index_mail *mail)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const struct mail_cache_field *all_cache_fields;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen mail_cache_register_get_list(_mail->box->cache,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen for (i = 0; i < count; i++) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (strncasecmp(all_cache_fields[i].name, "hdr.", 4) != 0)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (!mail_cache_field_want_add(_mail->transaction->cache_trans,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen array_idx_set(&mail->header_match, all_cache_fields[i].idx,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid index_mail_parse_header_init(struct index_mail *mail,
093d5c0cdf04c9190b6377e624206cdf85fe665aTimo Sirainen i_assert(!mail->data.header_parser_initialized);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen mail->header_data = buffer_create_dynamic(default_pool, 4096);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen mail->header_match_value = HEADER_MATCH_SKIP_COUNT;
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen mail->header_match_value += HEADER_MATCH_SKIP_COUNT;
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen /* wrapped, we'll have to clear the buffer */
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen mail->header_match_value = HEADER_MATCH_SKIP_COUNT;
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen array_idx_set(&mail->header_match, headers->idx[i],
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if (data->wanted_headers != NULL && data->wanted_headers != headers) {
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen array_idx_set(&mail->header_match, headers->idx[i],
45b2a27617d8475f71fdfc870690e46cd63849f2Timo Sirainen /* register also all the other headers that exist in cache file */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen index_mail_parse_header_register_all_wanted(mail);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen /* if we want sent date, it doesn't mean that we also want to cache
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen Date: header. if we have Date field's index set at this point we
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen know that we want it. otherwise add it and remember that we don't
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen want it cached. */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen field_idx = get_header_field_idx(mail->mail.mail.box, "Date",
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen match = array_get(&mail->header_match, &match_count);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen match[field_idx] == mail->header_match_value) {
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen /* cache Date: header */
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen } else if ((data->cache_fetch_fields & MAIL_FETCH_DATE) != 0 ||
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen /* parse Date: header, but don't cache it. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void index_mail_parse_finish_imap_envelope(struct index_mail *mail)
469a6cf705835ade57dcb59979b6e054207ae5d7Timo Sirainen mail->ibox->cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx;
b674bd911aaab7e8b1a77c106a0b5bccb603439fStephan Bosch imap_envelope_write(mail->data.envelope_data, str);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (mail_cache_field_can_add(_mail->transaction->cache_trans,
469a6cf705835ade57dcb59979b6e054207ae5d7Timo Sirainen index_mail_cache_add_idx(mail, cache_field_envelope,
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainenvoid index_mail_parse_header(struct message_part *part,
df459621b9124dfd88d56619ac84611f30fec854Stephan Bosch message_part_data_parse_from_header(mail->mail.data_pool, part, hdr);
946f22af116d5af80d5bbe1710ac121aa5acef71Stephan Bosch message_part_envelope_parse_from_header(mail->mail.data_pool,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* end of headers */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen match = array_get_modifiable(&mail->header_match, &count);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen !HEADER_MATCH_USABLE(mail, match[field_idx])) {
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen /* we don't want this header. */
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen /* beginning of a line. add the header name. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.start_pos = str_len(mail->header_data);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.line_num = data->parse_line_num;
60576cd64e6a537413cd90104f7e862f71d48c81Timo Sirainen str_append_n(mail->header_data, hdr->middle, hdr->middle_len);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen /* remember that we saw this header so we don't add it to
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen cache as nonexistent. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append_n(mail->header_data, hdr->value, hdr->value_len);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data->parse_line.end_pos = str_len(mail->header_data);
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen array_append(&mail->header_lines, &data->parse_line, 1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenindex_mail_parse_part_header_cb(struct message_part *part,
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenindex_mail_parse_header_cb(struct message_header_line *hdr,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen index_mail_parse_header(mail->data.parts, hdr, mail);
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainenindex_mail_cache_parse_init(struct mail *_mail, struct istream *input)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen /* we're doing everything for now, figure out later if we want to
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen save them. */
e78c6f8ecf4927dd579df8bcfd600b96e3f3a2f0Josef 'Jeff' Sipek /* Don't unnecessarily waste time generating a snippet, since it's
e78c6f8ecf4927dd579df8bcfd600b96e3f3a2f0Josef 'Jeff' Sipek not as cheap as the others to generate. */
e78c6f8ecf4927dd579df8bcfd600b96e3f3a2f0Josef 'Jeff' Sipek if (index_mail_want_cache(mail, MAIL_CACHE_BODY_SNIPPET))
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen mail->data.tee_stream = tee_i_stream_create(input);
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen input = tee_i_stream_create_child(mail->data.tee_stream);
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen input2 = tee_i_stream_create_child(mail->data.tee_stream);
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen message_parser_init(mail->mail.data_pool, input,
dd0dea1fdd913a04bae16e82dd66d67571a5f6c2Timo Sirainenstatic void index_mail_init_parser(struct index_mail *mail)
8b5b1f6cb19253dfd7821fcef8e9b7e95e6caf3aTimo Sirainen if (message_parser_deinit_from_parts(&data->parser_ctx, &parts, &error) < 0) {
489301ee88b2174e3171875e979e667de2c4a174Timo Sirainen index_mail_set_message_parts_corrupted(&mail->mail.mail, error);
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen data->parser_ctx = message_parser_init(mail->mail.data_pool,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainenint index_mail_parse_headers(struct index_mail *mail,
20195ef995a4eb63a282283db63f1dc0605323e0Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen if (mail_get_hdr_stream_because(&mail->mail.mail, NULL, reason, &input) < 0)
1045a1d4c191a14867cde0d5cea9e4ac5e36f85fTimo Sirainen if (data->parts == NULL || data->save_bodystructure_header) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* initialize bodystructure parsing in case we read the whole
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen message_parser_parse_header(data->parser_ctx, &data->hdr_size,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* just read the header */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen message_parse_header(data->stream, &data->hdr_size,
50de46721446795c42943c572625f2f1a9abfe01Timo Sirainen if (index_mail_stream_check_failure(mail) < 0)
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenimap_envelope_parse_callback(struct message_header_line *hdr,
946f22af116d5af80d5bbe1710ac121aa5acef71Stephan Bosch message_part_envelope_parse_from_header(mail->mail.data_pool,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenint index_mail_headers_get_envelope(struct index_mail *mail)
3889d05019a072a602f7a8c1eeb8a6f1c1362720Timo Sirainen mail->ibox->cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen header_ctx = mailbox_header_lookup_init(mail->mail.mail.box,
00db1d630a723113609598e28acbae4d416e0cb4Timo Sirainen if (mail_get_header_stream(&mail->mail.mail, header_ctx, &stream) < 0) {
9db263f2b9ab771fbf9a2bff44a245c45eaef218Timo Sirainen if (mail->data.envelope == NULL && stream != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we got the headers from cache - parse them to get the
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen message_parse_header(stream, NULL, hdr_parser_flags,
d052dcfff0c96a0af17a3158e51f709edf4b93a1Timo Sirainen index_mail_stream_log_failure_for(mail, stream);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic size_t get_header_size(buffer_t *buffer, size_t pos)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic int index_mail_header_is_parsed(struct index_mail *mail,
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen match = array_get(&mail->header_match, &count);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (field_idx < count && HEADER_MATCH_USABLE(mail, match[field_idx]))
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return (match[field_idx] & HEADER_MATCH_FLAG_FOUND) != 0 ? 1 : 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool skip_header(const unsigned char **data, size_t len)
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen const unsigned char *p = *data;
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen for (i = 0; i < len; i++) {
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen if (p[i] == ':')
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen for (i++; i < len; i++) {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainenstatic const char *const *
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenindex_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen const unsigned char *header, *value_start, *value_end;
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen line_idx = array_idx(&mail->header_match_lines, field_idx);
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen p_array_init(&header_values, mail->mail.data_pool, 4);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen lines = array_get(&mail->header_lines, &lines_count);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen for (i = first_line_idx; i < lines_count; i++) {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen if (lines[i].field_idx != lines[first_line_idx].field_idx)
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen /* skip header: and drop ending LF */
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen if (skip_header(&value_start, value_end - value_start)) {
1e242794e7a4f653f18fbb8edfe9ccec489a3a08Timo Sirainen if (value_start != value_end && value_end[-1] == '\n')
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen value = p_strndup(mail->mail.data_pool, value_start,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenindex_mail_get_raw_headers(struct index_mail *mail, const char *field,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char *const **value_r)
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen field_idx = get_header_field_idx(_mail->box, field,
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (mail_cache_lookup_headers(_mail->transaction->cache_view, dest,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* not in cache / error - first see if it's already parsed */
ea5a14af8ae816feda08937084954e3912748181Timo Sirainen /* don't try to parse headers recursively. we're here
ea5a14af8ae816feda08937084954e3912748181Timo Sirainen because message size was wrong and istream-mail
ea5a14af8ae816feda08937084954e3912748181Timo Sirainen wants to log some cached headers. */
ea5a14af8ae816feda08937084954e3912748181Timo Sirainen i_assert(mail->mail.mail.lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE);
5dabb8e733a8af2337eb543f782eb6c43ea462dcTimo Sirainen index_mail_header_is_parsed(mail, field_idx) < 0) {
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen const char *reason = index_mail_cache_reason(_mail,
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen headers_ctx = mailbox_header_lookup_init(_mail->box,
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen ret = index_mail_parse_headers(mail, headers_ctx, reason);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if ((ret = index_mail_header_is_parsed(mail, field_idx)) <= 0) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* not found */
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen *value_r = p_new(mail->mail.data_pool, const char *, 1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *value_r = index_mail_get_parsed_header(mail, field_idx);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen data = buffer_get_modifiable_data(dest, &len);
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen /* cached as nonexistent. */
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen *value_r = p_new(mail->mail.data_pool, const char *, 1);
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen p_array_init(&header_values, mail->mail.data_pool, 4);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* cached. skip "header name: " parts in dest. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < len; i++) {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* @UNSAFE */
96a464e3e417557153272c964fc8a0e9bb6d6b86Timo Sirainenstatic int unfold_header(pool_t pool, const char **_str)
f38854c96aef76e0c859df4e8f7303325b7ae8a1Timo Sirainen unsigned int i, j;
f38854c96aef76e0c859df4e8f7303325b7ae8a1Timo Sirainen /* @UNSAFE */
f38854c96aef76e0c859df4e8f7303325b7ae8a1Timo Sirainen new_str = p_malloc(pool, i + strlen(str+i) + 1);
96a464e3e417557153272c964fc8a0e9bb6d6b86Timo Sirainen /* corrupted */
66f9709e0c7604e2282b930b6a48fe9f0dd20ab8Timo Sirainen for (i = 0; i < len; i++) {
96a464e3e417557153272c964fc8a0e9bb6d6b86Timo Sirainenindex_mail_headers_decode(struct index_mail *mail, const char *const **_list,
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen decoded_list = p_new(mail->mail.data_pool, const char *, count + 1);
dce5a2719df4fc64a8762d2aa94ba98dcf9cd6feTimo Sirainen for (i = 0; i < count; i++) {
b9a664472557182cff0825a2285b8fca39f72947Timo Sirainen /* unfold all lines into a single line */
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen if (unfold_header(mail->mail.data_pool, &input) < 0)
b9a664472557182cff0825a2285b8fca39f72947Timo Sirainen /* decode MIME encoded-words. decoding may also add new LFs. */
82d3a1d1594ed93d04d7bf999027b3e5104de6e4Timo Sirainen message_header_decode_utf8((const unsigned char *)input,
66f9709e0c7604e2282b930b6a48fe9f0dd20ab8Timo Sirainen /* replace NULs with spaces */
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen input = p_strdup(mail->mail.data_pool, str_c(str));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenint index_mail_get_headers(struct mail *_mail, const char *field,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen bool decode_to_utf8, const char *const **value_r)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
96a464e3e417557153272c964fc8a0e9bb6d6b86Timo Sirainen if (index_mail_get_raw_headers(mail, field, value_r) < 0)
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ret = index_mail_headers_decode(mail, value_r, UINT_MAX);
7522446d6514e5593c9d4d7e4beacd328301cb23Aki Tuomi mail_set_mail_cache_corrupted(_mail, "Broken header %s",
073f965351846b8c97347b882c441dc336965e26Timo Sirainen i_panic("BUG: Broken header %s for mail UID %u "
073f965351846b8c97347b882c441dc336965e26Timo Sirainen "wasn't fixed by re-parsing the header",
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenint index_mail_get_first_header(struct mail *_mail, const char *field,
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
96a464e3e417557153272c964fc8a0e9bb6d6b86Timo Sirainen if (index_mail_get_raw_headers(mail, field, &list) < 0)
96a464e3e417557153272c964fc8a0e9bb6d6b86Timo Sirainen ret = index_mail_headers_decode(mail, &list, 1);
7522446d6514e5593c9d4d7e4beacd328301cb23Aki Tuomi mail_set_mail_cache_corrupted(_mail, "Broken header %s",
d48ab236010e588c7b52e54db47fe9842a2e27e8Timo Sirainen /* retry by parsing the full header */
073f965351846b8c97347b882c441dc336965e26Timo Sirainen i_panic("BUG: Broken header %s for mail UID %u "
073f965351846b8c97347b882c441dc336965e26Timo Sirainen "wasn't fixed by re-parsing the header",
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainenheader_cache_callback(struct header_filter_istream *input ATTR_UNUSED,
6202c9d2492d33ff28ba61a5c57c6768df9577d0Timo Sirainen bool *matched ATTR_UNUSED, struct index_mail *mail)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenint index_mail_get_header_stream(struct mail *_mail,
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
cb1e7cb6766cfb18900e600961fb8b45a4dffaf8Timo Sirainen /* read through the previous filter_stream. this makes sure
cb1e7cb6766cfb18900e600961fb8b45a4dffaf8Timo Sirainen that the fields are added to cache, and most importantly it
cb1e7cb6766cfb18900e600961fb8b45a4dffaf8Timo Sirainen resets header_parser_initialized=FALSE so we don't assert
cb1e7cb6766cfb18900e600961fb8b45a4dffaf8Timo Sirainen while (i_stream_read_more(mail->data.filter_stream, &data, &size) > 0)
cb1e7cb6766cfb18900e600961fb8b45a4dffaf8Timo Sirainen i_stream_skip(mail->data.filter_stream, size);
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen /* we have to parse the header. */
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen index_mail_cache_reason(_mail, "bodystructure");
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen if (index_mail_parse_headers(mail, headers, reason) < 0)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (mail_cache_lookup_headers(_mail->transaction->cache_view, dest,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* not in cache / error */
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen unsigned int first_not_found = UINT_MAX, not_found_count = 0;
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen for (unsigned int i = 0; i < headers->count; i++) {
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen if (mail_cache_field_exists(_mail->transaction->cache_view,
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen reason = "BUG: all headers seem to exist in cache";
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen reason = index_mail_cache_reason(_mail, t_strdup_printf(
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen "%u/%u headers not cached (first=%s)",
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen not_found_count, headers->count, headers->name[first_not_found]));
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen if (mail_get_hdr_stream_because(_mail, NULL, reason, &input) < 0)