index-mail-headers.c revision e192a3b1ca8ae857e7d87298ea507d32977ba570
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (C) 2003-2006 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int *idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char **name;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int header_line_cmp(const void *p1, const void *p2)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct index_mail_line *l1 = p1, *l2 = p2;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen diff = (int)l1->field_idx - (int)l2->field_idx;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenstatic void index_mail_parse_header_finish(struct index_mail *mail)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen unsigned int i, j, count, match_idx, match_count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lines = array_get_modifiable(&mail->header_lines, &count);
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 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 /* go through all the header lines we found */
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen /* matches and header lines are both sorted, all matches
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen until lines[i] weren't found */
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. */
83c21c990eb2a370f0da56240e73dac846f4acc3Timo Sirainen if (match[match_idx] == mail->header_match_value &&
83c21c990eb2a370f0da56240e73dac846f4acc3Timo Sirainen mail_cache_field_exists(mail->trans->cache_view,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* this header doesn't exist. remember that. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* save index to first header line */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match_lines, match_idx, &j);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* header is already cached */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* buffer contains: { uint32_t line_num[], 0, header texts }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen noncontiguous is just a small optimization.. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (; i < j; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(buf, header + lines[i].start_pos,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen buffer_append(buf, header + lines[i].start_pos,
65b7beb7cefce89e175920ef6c16118b1b0dbfb3Timo Sirainen index_mail_cache_add_idx(mail, lines[i].field_idx,
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 /* this header doesn't exist. remember that. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add_idx(mail, match_idx, NULL, 0);
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 /* first check that it isn't already added in this session */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (match[cache_field] & ~1) == mail->header_match_value)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strncasecmp(mail->data.all_cache_fields[i].name,
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 index_mail_cache_add_idx(mail, cache_field, NULL, 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic unsigned int
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenget_header_field_idx(struct index_mailbox *ibox, const char *field)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen header_field.name = t_strconcat("hdr.", field, NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_cache_register_fields(ibox->cache, &header_field, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid index_mail_parse_header_init(struct index_mail *mail,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->header_data = buffer_create_dynamic(default_pool, 4096);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* wrapped, we'll have to clear the buffer */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match, headers->idx[i],
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen if (mail->wanted_headers != NULL && mail->wanted_headers != headers) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_idx_set(&mail->header_match, headers->idx[i],
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_cache_register_get_list(mail->ibox->cache,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail->data_pool, &mail->data.all_cache_fields_count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void index_mail_parse_finish_imap_envelope(struct index_mail *mail)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen imap_envelope_write_part_data(mail->data.envelope_data, str);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add(mail, MAIL_CACHE_IMAP_ENVELOPE,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid index_mail_parse_header(struct message_part *part,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen imap_bodystructure_parse_header(mail->data_pool, part, hdr);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* end of headers */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen cache_field_name = t_strconcat("hdr.", hdr->name, NULL);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* we don't want this field */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mail_cache_field_want_add(mail->trans->cache_trans,
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] & ~1) != mail->header_match_value)) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* we don't need to do anything with this header */
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_n(mail->header_data, hdr->middle, hdr->middle_len);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen str_append_n(mail->header_data, hdr->value, hdr->value_len);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen data->parse_line.end_pos = str_len(mail->header_data);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen array_append(&mail->header_lines, &data->parse_line, 1);
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainenindex_mail_parse_part_header_cb(struct message_part *part,
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen struct message_header_line *hdr, void *context)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenindex_mail_parse_header_cb(struct message_header_line *hdr, void *context)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen index_mail_parse_header(mail->data.parts, hdr, mail);
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainenint index_mail_parse_headers(struct index_mail *mail,
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mail_get_stream(&mail->mail.mail, NULL, NULL) == NULL)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (data->parser_ctx == NULL && (data->parts == NULL ||
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* initialize bodystructure parsing in case we read the whole
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen (void)message_parser_deinit(&mail->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 /* just read the header */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen message_parse_header(data->stream, &data->hdr_size,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenimap_envelope_parse_callback(struct message_header_line *hdr, void *context)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenvoid index_mail_headers_get_envelope(struct index_mail *mail)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen header_ctx = mailbox_header_lookup_init(&mail->ibox->box,
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 Sirainenstatic size_t get_header_size(buffer_t *buffer, size_t pos)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen const unsigned char *data;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic int index_mail_header_is_parsed(struct index_mail *mail,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen match = array_get(&mail->header_match, &count);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (match[field_idx] == mail->header_match_value)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen else if (match[field_idx] == mail->header_match_value + 1)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool skip_header(const unsigned char **data, size_t len)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const unsigned char *p = *data;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen for (i = 0; i < len; i++) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (p[i] == ':')
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen for (i++; i < len; i++) {
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenstatic const char *const *
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenindex_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const unsigned char *header, *value_start, *value_end;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const unsigned int *line_idx;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen line_idx = array_idx(&mail->header_match_lines, field_idx);
value_end--;
unsigned char *data;
unsigned int field_idx;
int ret;
headers);
if (ret < 0)
return NULL;
if (len == 0) {
for (i = 0; i < len; i++) {
struct istream *
return NULL;
return NULL;
struct mailbox_header_lookup_ctx *
const char *const *name;
const char **sorted_headers;
unsigned int i, count;
count++;
t_push();
for (i = 0; i < count; i++) {
for (i = 0; i < count; i++) {
t_pop();