index-mail-headers.c revision e192a3b1ca8ae857e7d87298ea507d32977ba570
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (C) 2003-2006 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "istream.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "array.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "buffer.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "str.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "message-date.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "message-parser.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "istream-header-filter.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "imap-envelope.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "imap-bodystructure.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "index-storage.h"
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen#include "index-mail.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include <stdlib.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstruct index_header_lookup_ctx {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox_header_lookup_ctx ctx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_t pool;
b5a084602a3dc2c118345f6d2990f47c1ff66264Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int *idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char **name;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen};
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int header_line_cmp(const void *p1, const void *p2)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct index_mail_line *l1 = p1, *l2 = p2;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int diff;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen diff = (int)l1->field_idx - (int)l2->field_idx;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen return diff != 0 ? diff :
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen (int)l1->line_num - (int)l2->line_num;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen}
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenstatic void index_mail_parse_header_finish(struct index_mail *mail)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen{
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen struct index_mail_line *lines;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const unsigned char *header, *data;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const uint8_t *match;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen buffer_t *buf;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen size_t data_size;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen unsigned int i, j, count, match_idx, match_count;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen bool noncontiguous;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_push();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lines = array_get_modifiable(&mail->header_lines, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen /* sort it first so fields are grouped together and ordered by
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen line number */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen qsort(lines, count, sizeof(*lines), header_line_cmp);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen match = array_get(&mail->header_match, &match_count);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen header = buffer_get_data(mail->header_data, NULL);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen /* go through all the header lines we found */
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen for (i = match_idx = 0; i < count; i = j) {
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen /* matches and header lines are both sorted, all matches
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen until lines[i] weren't found */
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen while (match_idx < lines[i].field_idx &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen match_idx < match_count) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* if match[] doesn't have header_match_value,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen it belongs to some older header parsing and we
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen just want to ignore it. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(match[match_idx] !=
83c21c990eb2a370f0da56240e73dac846f4acc3Timo Sirainen mail->header_match_value + 1);
83c21c990eb2a370f0da56240e73dac846f4acc3Timo Sirainen if (match[match_idx] == mail->header_match_value &&
83c21c990eb2a370f0da56240e73dac846f4acc3Timo Sirainen mail_cache_field_exists(mail->trans->cache_view,
83c21c990eb2a370f0da56240e73dac846f4acc3Timo Sirainen mail->data.seq,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen match_idx) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* this header doesn't exist. remember that. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add_idx(mail, match_idx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen NULL, 0);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen }
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen match_idx++;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (match_idx < match_count) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* save index to first header line */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen j = i + 1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match_lines, match_idx, &j);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen match_idx++;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!lines[i].cache) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* header is already cached */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen j = i + 1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen continue;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* buffer contains: { uint32_t line_num[], 0, header texts }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen noncontiguous is just a small optimization.. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_set_used_size(buf, 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(buf, &lines[i].line_num,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen sizeof(lines[i].line_num));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen noncontiguous = FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (j = i+1; j < count; j++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (lines[j].field_idx != lines[i].field_idx)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (lines[j].start_pos != lines[j-1].end_pos)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen noncontiguous = TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(buf, &lines[j].line_num,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen sizeof(lines[j].line_num));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append_zero(buf, sizeof(uint32_t));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (noncontiguous) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (; i < j; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(buf, header + lines[i].start_pos,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lines[i].end_pos -
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lines[i].start_pos);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen i--;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen } else {
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen buffer_append(buf, header + lines[i].start_pos,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lines[j-1].end_pos - lines[i].start_pos);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen data = buffer_get_data(buf, &data_size);
65b7beb7cefce89e175920ef6c16118b1b0dbfb3Timo Sirainen index_mail_cache_add_idx(mail, lines[i].field_idx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen data, data_size);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (; match_idx < match_count; match_idx++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (match[match_idx] == mail->header_match_value &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_cache_field_exists(mail->trans->cache_view,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data.seq, match_idx) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* this header doesn't exist. remember that. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add_idx(mail, match_idx, NULL, 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* set all non-found headers registered in cache */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < mail->data.all_cache_fields_count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int cache_field = mail->data.all_cache_fields[i].idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* first check that it isn't already added in this session */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (cache_field < match_count &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (match[cache_field] & ~1) == mail->header_match_value)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen continue;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strncasecmp(mail->data.all_cache_fields[i].name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "hdr.", 4) != 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen continue;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* check that it hadn't been added in some older session */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail_cache_field_exists(mail->trans->cache_view,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data.seq, cache_field) == 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add_idx(mail, cache_field, NULL, 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_pop();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic unsigned int
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenget_header_field_idx(struct index_mailbox *ibox, const char *field)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mail_cache_field header_field = {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen NULL, 0, MAIL_CACHE_FIELD_HEADER, 0,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen MAIL_CACHE_DECISION_TEMP
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen };
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_push();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen header_field.name = t_strconcat("hdr.", field, NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_cache_register_fields(ibox->cache, &header_field, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_pop();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return header_field.idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid index_mail_parse_header_init(struct index_mail *mail,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox_header_lookup_ctx *_headers)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct index_header_lookup_ctx *headers =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (struct index_header_lookup_ctx *)_headers;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->header_seq = mail->data.seq;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail->header_data == NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->header_data = buffer_create_dynamic(default_pool, 4096);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_array_init(&mail->header_lines, 32);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_array_init(&mail->header_match, 32);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_array_init(&mail->header_match_lines, 32);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_set_used_size(mail->header_data, 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_clear(&mail->header_lines);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_clear(&mail->header_match_lines);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->header_match_value += 2;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail->header_match_value == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* wrapped, we'll have to clear the buffer */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_clear(&mail->header_match);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->header_match_value = 2;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen }
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (headers != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < headers->count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match, headers->idx[i],
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen &mail->header_match_value);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen if (mail->wanted_headers != NULL && mail->wanted_headers != headers) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen headers = mail->wanted_headers;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < headers->count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match, headers->idx[i],
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen &mail->header_match_value);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mail->data.save_sent_date) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data.save_sent_date = FALSE;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen get_header_field_idx(mail->ibox, "Date"),
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen &mail->header_match_value);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* get a list of all currently cached fields. we'll later set those
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen headers that weren't found to empty. if this list is get later,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen it's possible that it has already changed (cache has no permanent
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen write locks, remember!) and we set some headers to empty even
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen though they really exist. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data.all_cache_fields =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_cache_register_get_list(mail->ibox->cache,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data_pool, &mail->data.all_cache_fields_count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void index_mail_parse_finish_imap_envelope(struct index_mail *mail)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen string_t *str;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen str = str_new(mail->data_pool, 256);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen imap_envelope_write_part_data(mail->data.envelope_data, str);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data.envelope = str_c(str);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add(mail, MAIL_CACHE_IMAP_ENVELOPE,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen str_data(str), str_len(str));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid index_mail_parse_header(struct message_part *part,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_header_line *hdr,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct index_mail *mail)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct index_mail_data *data = &mail->data;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *cache_field_name;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int field_idx, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen uint8_t *match;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen data->parse_line_num++;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (data->save_bodystructure_header) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(part != NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen imap_bodystructure_parse_header(mail->data_pool, part, hdr);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (data->save_envelope) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen imap_envelope_parse_header(mail->data_pool,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen &data->envelope_data, hdr);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (hdr == NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_parse_finish_imap_envelope(mail);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (hdr == NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* end of headers */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (data->sent_date.time != (uint32_t)-1) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen &data->sent_date,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen sizeof(data->sent_date));
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_header_finish(mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->save_bodystructure_header = FALSE;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (!hdr->continued) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen t_push();
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen cache_field_name = t_strconcat("hdr.", hdr->name, NULL);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parse_line.field_idx =
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail_cache_register_lookup(mail->ibox->cache,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen cache_field_name);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen t_pop();
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen field_idx = data->parse_line.field_idx;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (field_idx == (unsigned int)-1) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* we don't want this field */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (!hdr->continued) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parse_line.cache =
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail_cache_field_want_add(mail->trans->cache_trans,
61e84692827b6a64912343f515c984853021483aTimo Sirainen data->seq, field_idx);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen match = array_get_modifiable(&mail->header_match, &count);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (field_idx < count && match[field_idx] == mail->header_match_value) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* first header */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen match[field_idx]++;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen } else if (!data->parse_line.cache &&
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen (field_idx >= count ||
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen (match[field_idx] & ~1) != mail->header_match_value)) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* we don't need to do anything with this header */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (!hdr->continued) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parse_line.start_pos = str_len(mail->header_data);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parse_line.line_num = data->parse_line_num;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen str_append(mail->header_data, hdr->name);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen str_append_n(mail->header_data, hdr->middle, hdr->middle_len);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen str_append_n(mail->header_data, hdr->value, hdr->value_len);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (!hdr->no_newline)
18ffea71d9beeec3cc1d400f751926ee72807f62Timo Sirainen str_append(mail->header_data, "\n");
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (!hdr->continues) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parse_line.end_pos = str_len(mail->header_data);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen array_append(&mail->header_lines, &data->parse_line, 1);
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen }
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen}
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainenstatic void
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainenindex_mail_parse_part_header_cb(struct message_part *part,
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen struct message_header_line *hdr, void *context)
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen{
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen struct index_mail *mail = context;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_header(part, hdr, mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic void
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenindex_mail_parse_header_cb(struct message_header_line *hdr, void *context)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct index_mail *mail = context;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_header(mail->data.parts, hdr, mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainenint index_mail_parse_headers(struct index_mail *mail,
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen struct mailbox_header_lookup_ctx *headers)
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen{
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen struct index_mail_data *data = &mail->data;
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen uoff_t old_offset;
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mail_get_stream(&mail->mail.mail, NULL, NULL) == NULL)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_header_init(mail, headers);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (data->parser_ctx == NULL && (data->parts == NULL ||
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->save_bodystructure_header)) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* initialize bodystructure parsing in case we read the whole
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen message. */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (data->parser_ctx != NULL)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen (void)message_parser_deinit(&mail->data.parser_ctx);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parser_ctx =
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen message_parser_init(mail->data_pool, data->stream);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen message_parser_parse_header(data->parser_ctx, &data->hdr_size,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_part_header_cb,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen } else {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* just read the header */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen message_parse_header(data->stream, &data->hdr_size,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_header_cb, mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->hdr_size_set = TRUE;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->access_part &= ~PARSE_HDR;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen i_stream_seek(data->stream, old_offset);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return 0;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic void
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenimap_envelope_parse_callback(struct message_header_line *hdr, void *context)
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct index_mail *mail = context;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen imap_envelope_parse_header(mail->data_pool,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen &mail->data.envelope_data, hdr);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (hdr == NULL)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_finish_imap_envelope(mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenvoid index_mail_headers_get_envelope(struct index_mail *mail)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct mailbox_header_lookup_ctx *header_ctx;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct istream *stream;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen uoff_t old_offset;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen old_offset = mail->data.stream == NULL ? 0 :
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail->data.stream->v_offset;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail->data.save_envelope = TRUE;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen header_ctx = mailbox_header_lookup_init(&mail->ibox->box,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen imap_envelope_headers);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen stream = mail_get_header_stream(&mail->mail.mail, header_ctx);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mail->data.envelope == NULL && stream != NULL) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* we got the headers from cache - parse them to get the
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen envelope */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen message_parse_header(stream, NULL,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen imap_envelope_parse_callback, mail);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail->data.save_envelope = FALSE;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_header_lookup_deinit(&header_ctx);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mail->data.stream != NULL)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen i_stream_seek(mail->data.stream, old_offset);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic size_t get_header_size(buffer_t *buffer, size_t pos)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen const unsigned char *data;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen size_t i, size;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data = buffer_get_data(buffer, &size);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen i_assert(pos <= size);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen for (i = pos; i < size; i++) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (data[i] == '\n') {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (i+1 == size ||
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen (data[i+1] != ' ' && data[i+1] != '\t'))
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return i - pos;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return size - pos;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic int index_mail_header_is_parsed(struct index_mail *mail,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen unsigned int field_idx)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const uint8_t *match;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen match = array_get(&mail->header_match, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (field_idx >= count)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return -1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (match[field_idx] == mail->header_match_value)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen else if (match[field_idx] == mail->header_match_value + 1)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return -1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool skip_header(const unsigned char **data, size_t len)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const unsigned char *p = *data;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen size_t i;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen for (i = 0; i < len; i++) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (p[i] == ':')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen if (i == len)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen return FALSE;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen for (i++; i < len; i++) {
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen if (!IS_LWSP(p[i]))
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen break;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen }
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen *data = p + i;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen return TRUE;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen}
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenstatic const char *const *
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenindex_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen{
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen ARRAY_DEFINE(header_values, const char *);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const struct index_mail_line *lines;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const unsigned char *header, *value_start, *value_end;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const unsigned int *line_idx;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const char *value;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen unsigned int i, lines_count, first_line_idx;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen line_idx = array_idx(&mail->header_match_lines, field_idx);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen i_assert(*line_idx != 0);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen first_line_idx = *line_idx - 1;
p_array_init(&header_values, mail->data_pool, 4);
header = buffer_get_data(mail->header_data, NULL);
lines = array_get(&mail->header_lines, &lines_count);
for (i = first_line_idx; i < lines_count; i++) {
if (lines[i].field_idx != lines[first_line_idx].field_idx)
break;
/* skip header: and drop ending LF */
value_start = header + lines[i].start_pos;
value_end = header + lines[i].end_pos;
if (skip_header(&value_start, value_end - value_start)) {
if (value_start != value_end && value_end[-1] == '\n')
value_end--;
value = p_strndup(mail->data_pool, value_start,
value_end - value_start);
array_append(&header_values, &value, 1);
}
}
value = NULL;
array_append(&header_values, &value, sizeof(value));
return array_idx(&header_values, 0);
}
const char *const *index_mail_get_headers(struct mail *_mail, const char *field)
{
struct index_mail *mail = (struct index_mail *)_mail;
const char *headers[2], *value;
struct mailbox_header_lookup_ctx *headers_ctx;
unsigned char *data;
unsigned int field_idx;
string_t *dest;
size_t i, len;
int ret;
ARRAY_DEFINE(header_values, const char *);
i_assert(field != NULL);
field_idx = get_header_field_idx(mail->ibox, field);
dest = str_new(mail->data_pool, 128);
if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
mail->data.seq, &field_idx, 1) <= 0) {
/* not in cache / error - first see if it's already parsed */
p_free(mail->data_pool, dest);
if (mail->header_seq == mail->data.seq) {
ret = index_mail_header_is_parsed(mail, field_idx);
if (ret != -1) {
return ret == 0 ? NULL :
index_mail_get_parsed_header(mail,
field_idx);
}
}
/* parse */
headers[0] = field; headers[1] = NULL;
headers_ctx = mailbox_header_lookup_init(&mail->ibox->box,
headers);
ret = index_mail_parse_headers(mail, headers_ctx);
mailbox_header_lookup_deinit(&headers_ctx);
if (ret < 0)
return NULL;
ret = index_mail_header_is_parsed(mail, field_idx);
i_assert(ret != -1);
return ret == 0 ? NULL :
index_mail_get_parsed_header(mail, field_idx);
}
data = buffer_get_modifiable_data(dest, &len);
if (len == 0) {
/* cached as non-existing. */
return p_new(mail->data_pool, const char *, 1);
}
p_array_init(&header_values, mail->data_pool, 4);
/* cached. skip "header name: " parts in dest. */
for (i = 0; i < len; i++) {
if (data[i] == ':') {
if (i+1 != len && data[++i] == ' ') i++;
/* @UNSAFE */
len = get_header_size(dest, i);
data[i + len] = '\0';
value = (const char *)data + i;
i += len + 1;
array_append(&header_values, &value, sizeof(value));
}
}
value = NULL;
array_append(&header_values, &value, sizeof(value));
return array_idx(&header_values, 0);
}
const char *index_mail_get_first_header(struct mail *mail, const char *field)
{
const char *const *list = index_mail_get_headers(mail, field);
return list == NULL ? NULL : list[0];
}
static void header_cache_callback(struct message_header_line *hdr,
bool *matched, void *context)
{
struct index_mail *mail = context;
if (hdr != NULL && hdr->eoh)
*matched = FALSE;
index_mail_parse_header(NULL, hdr, mail);
}
struct istream *
index_mail_get_header_stream(struct mail *_mail,
struct mailbox_header_lookup_ctx *_headers)
{
struct index_mail *mail = (struct index_mail *)_mail;
struct index_header_lookup_ctx *headers =
(struct index_header_lookup_ctx *)_headers;
string_t *dest;
if (mail->data.save_bodystructure_header) {
/* we have to parse the header. */
if (index_mail_parse_headers(mail, _headers) < 0)
return NULL;
}
dest = str_new(mail->data_pool, 256);
if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
mail->data.seq, headers->idx,
headers->count) > 0) {
if (mail->data.filter_stream != NULL)
i_stream_destroy(&mail->data.filter_stream);
mail->data.filter_stream =
i_stream_create_from_data(default_pool,
str_data(dest),
str_len(dest));
return mail->data.filter_stream;
}
/* not in cache / error */
p_free(mail->data_pool, dest);
if (mail_get_stream(&mail->mail.mail, NULL, NULL) == NULL)
return NULL;
if (mail->data.filter_stream != NULL)
i_stream_destroy(&mail->data.filter_stream);
index_mail_parse_header_init(mail, _headers);
mail->data.filter_stream =
i_stream_create_header_filter(mail->data.stream,
HEADER_FILTER_INCLUDE |
HEADER_FILTER_HIDE_BODY,
headers->name, headers->count,
header_cache_callback, mail);
return mail->data.filter_stream;
}
struct mailbox_header_lookup_ctx *
index_header_lookup_init(struct mailbox *box, const char *const headers[])
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
struct mail_cache_field *fields, header_field = {
NULL, 0, MAIL_CACHE_FIELD_HEADER, 0,
MAIL_CACHE_DECISION_TEMP
};
struct index_header_lookup_ctx *ctx;
const char *const *name;
const char **sorted_headers;
pool_t pool;
unsigned int i, count;
i_assert(*headers != NULL);
for (count = 0, name = headers; *name != NULL; name++)
count++;
t_push();
/* @UNSAFE: headers need to be sorted for filter stream. */
sorted_headers = t_new(const char *, count);
memcpy(sorted_headers, headers, count * sizeof(*sorted_headers));
qsort(sorted_headers, count, sizeof(*sorted_headers), strcasecmp_p);
headers = sorted_headers;
/* @UNSAFE */
fields = t_new(struct mail_cache_field, count);
for (i = 0; i < count; i++) {
header_field.name = t_strconcat("hdr.", headers[i], NULL);
fields[i] = header_field;
}
mail_cache_register_fields(ibox->cache, fields, count);
pool = pool_alloconly_create("index_header_lookup_ctx", 1024);
ctx = p_new(pool, struct index_header_lookup_ctx, 1);
ctx->ctx.box = box;
ctx->pool = pool;
ctx->count = count;
ctx->idx = p_new(pool, unsigned int, count);
ctx->name = p_new(pool, const char *, count);
/* @UNSAFE */
for (i = 0; i < count; i++) {
ctx->idx[i] = fields[i].idx;
ctx->name[i] = p_strdup(pool, headers[i]);
}
t_pop();
return &ctx->ctx;
}
void index_header_lookup_deinit(struct mailbox_header_lookup_ctx *_ctx)
{
struct index_header_lookup_ctx *ctx =
(struct index_header_lookup_ctx *)_ctx;
pool_unref(ctx->pool);
}