index-mail-headers.c revision 9db263f2b9ab771fbf9a2bff44a245c45eaef218
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int *idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char **name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int header_line_cmp(const void *p1, const void *p2)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct index_mail_line *l1 = p1, *l2 = p2;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen diff = (int)l1->field_idx - (int)l2->field_idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void index_mail_parse_header_finish(struct index_mail *mail)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen size_t i, j, size, data_size, match_idx, match_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines = buffer_get_modifyable_data(mail->header_lines, &size);
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 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 if (match[match_idx] == mail->header_match_value) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* this header doesn't exist. remember that. */
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,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_add(mail->trans->cache_trans, mail->data.seq,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen if (match[match_idx] == mail->header_match_value) {
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen /* this header doesn't exist. remember that. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid index_mail_parse_header_init(struct index_mail *mail,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_create_dynamic(default_pool, 4096, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_create_dynamic(default_pool, 256, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_create_dynamic(default_pool, 64, (size_t)-1);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_create_dynamic(default_pool, 256, (size_t)-1);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen buffer_set_used_size(mail->header_offsets, 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_write(mail->header_match, headers->idx[i],
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail->wanted_headers != NULL && mail->wanted_headers != headers) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_write(mail->header_match, headers->idx[i],
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void index_mail_parse_finish_imap_envelope(struct index_mail *mail)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_envelope_write_part_data(mail->data.envelope_data, str);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_add(mail->trans->cache_trans, mail->data.seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen MAIL_CACHE_ENVELOPE, str_data(str), str_len(str));
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainenint index_mail_parse_header(struct message_part *part,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_bodystructure_parse_header(mail->pool, part, hdr);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* end of headers */
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* not found */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen mail_cache_add(mail->trans->cache_trans, data->seq,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (data->save_sent_date && strcasecmp(hdr->name, "Date") == 0) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* 0 == parse error */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cache_field_name = t_strconcat("hdr.", hdr->name, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we don't want this field */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen decision = mail_cache_field_get_decision(mail->ibox->cache,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_field_exists(mail->trans->cache_view,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* already cached */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen match = buffer_get_modifyable_data(mail->header_match, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen (match[field_idx] & ~1) != mail->header_match_value) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we don't need to do anything with this header */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (match[field_idx] == mail->header_match_value) {
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* first header */
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);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* save the offset to first header */
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);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(mail->header_lines, &data->parse_line,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenindex_mail_parse_header_cb(struct message_part *part,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct message_header_line *hdr, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)index_mail_parse_header(part, hdr, mail);
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainenint index_mail_parse_headers(struct index_mail *mail,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (data->parts == NULL && data->parser_ctx == NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* initialize bodystructure parsing in case we read the whole
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen message_parser_init(mail->pool, data->stream);
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen message_parser_parse_header(data->parser_ctx, &data->hdr_size,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* just read the header */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen message_parse_header(data->parts, data->stream, &data->hdr_size,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenimap_envelope_parse_callback(struct message_part *part __attr_unused__,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct message_header_line *hdr, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen imap_envelope_parse_header(mail->pool, &mail->data.envelope_data, hdr);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid index_mail_headers_get_envelope(struct index_mail *mail)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header_ctx = mailbox_header_lookup_init(&mail->ibox->box,
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 Sirainenstatic unsigned int
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenget_header_field_idx(struct index_mailbox *ibox, const char *field)
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 mail_cache_register_fields(ibox->cache, &header_field, 1);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic size_t get_header_size(buffer_t *buffer, size_t pos)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen const unsigned char *data;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic int index_mail_header_is_parsed(struct index_mail *mail,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen match = buffer_get_data(mail->header_match, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen if (match[field_idx] == mail->header_match_value)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen else if (match[field_idx] == mail->header_match_value + 1)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenstatic const char *
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainenindex_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen const unsigned char *data;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen offsets = buffer_get_data(mail->header_offsets, &size);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen i_assert(field_idx * sizeof(*offsets) >= size &&
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);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenconst char *index_mail_get_header(struct mail *_mail, const char *field)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const unsigned char *data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen field_idx = get_header_field_idx(mail->ibox, field);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen /* not in cache / error - first see if it's already parsed */
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen ret = index_mail_header_is_parsed(mail, field_idx);
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen headers_ctx = mailbox_header_lookup_init(&mail->ibox->box,
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen ret = index_mail_parse_headers(mail, headers_ctx);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen ret = index_mail_header_is_parsed(mail, field_idx);
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen index_mail_get_parsed_header(mail, field_idx);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* cached. skip "header name: " in dest. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < len; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* return only the first field in case there's multiple. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void header_cache_callback(struct message_header_line *hdr,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)index_mail_parse_header(NULL, hdr, mail);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen /* we have to parse the header. */
a24b0595f0f7d3925d4c9ac26fa503ff87c43e43Timo Sirainen if (index_mail_parse_headers(mail, _headers) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* not in cache / error */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen i_stream_create_header_filter(mail->data.stream,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenindex_header_lookup_init(struct mailbox *box, const char *const headers[])
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct index_mailbox *ibox = (struct index_mailbox *)box;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache_field *fields, header_field = {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *const *name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (size = 0, name = headers; *name != NULL; name++)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* headers need to be sorted for filter stream. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memcpy(sorted_headers, headers, size * sizeof(*sorted_headers));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen qsort(sorted_headers, size, sizeof(*sorted_headers),
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));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen fields = buffer_get_modifyable_data(buf, &size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_register_fields(ibox->cache, fields, size);
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 /* @UNSAFE */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < size; i++) {