istream-header-filter.c revision 5695ec03a0cc4836896e46a01bb9336782aee326
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Copyright (c) 2003-2017 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "array.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "sort.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "message-parser.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "istream-private.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "istream-header-filter.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct header_filter_istream {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream_private istream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool_t pool;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen struct message_header_parser_ctx *hdr_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char **headers;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int headers_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen header_filter_callback *callback;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen void *context;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_t *hdr_buf;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_size header_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t skip_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t last_lf_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int cur_line, parsed_lines;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ARRAY(unsigned int) match_change_lines;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool header_read:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool seen_eoh:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool header_parsed:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool headers_edited:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool exclude:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool crlf:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool crlf_preserve:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool hide_body:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool add_missing_eoh:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool end_body_with_lf:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool last_lf_added:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool last_orig_crlf:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool last_added_newline:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool eoh_not_matched:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool callbacks_called:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool prev_matched:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void i_stream_header_filter_destroy(struct iostream_private *stream)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct header_filter_istream *mstream =
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (struct header_filter_istream *)stream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->hdr_ctx != NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (array_is_created(&mstream->match_change_lines))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_free(&mstream->match_change_lines);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool_unref(&mstream->pool);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic ssize_t
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenread_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ssize_t ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->hide_body) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.istream.eof = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (pos <= body_highwater_size) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(pos == body_highwater_size ||
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (mstream->end_body_with_lf &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pos+1 == body_highwater_size));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = i_stream_read(mstream->istream.parent);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.istream.stream_errno =
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.parent->stream_errno;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.istream.eof = mstream->istream.parent->eof;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret <= 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen data = mstream->hdr_buf->data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pos = mstream->hdr_buf->used;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(pos > 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->end_body_with_lf && data[pos-1] != '\n' &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret == -1 && mstream->istream.istream.eof) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* add missing trailing LF to body */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->crlf)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_append_c(mstream->hdr_buf, '\r');
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.buffer = mstream->hdr_buf->data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.pos = mstream->hdr_buf->used;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return mstream->hdr_buf->used - pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_append(mstream->hdr_buf, data + body_highwater_size,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pos - body_highwater_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(ret > 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.pos = pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int cmp_uint(const unsigned int *i1, const unsigned int *i2)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return *i1 < *i2 ? -1 :
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (*i1 > *i2 ? 1 : 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic bool match_line_changed(struct header_filter_istream *mstream)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (!array_is_created(&mstream->match_change_lines))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return array_bsearch(&mstream->match_change_lines, &mstream->cur_line,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen cmp_uint) != NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void add_eol(struct header_filter_istream *mstream, bool orig_crlf)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->crlf || (orig_crlf && mstream->crlf_preserve))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_append(mstream->hdr_buf, "\r\n", 2);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen else
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->last_orig_crlf = orig_crlf;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->last_added_newline = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic ssize_t hdr_stream_update_pos(struct header_filter_istream *mstream)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ssize_t ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(ret >= 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.pos = pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_header_line *hdr;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t highwater_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t max_buffer_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ssize_t ret, ret2;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int hdr_ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->hdr_ctx == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->hdr_ctx =
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen message_parse_header_init(mstream->istream.parent,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen NULL, 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* remove skipped data from hdr_buf */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_copy(mstream->hdr_buf, 0,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.pos -= mstream->istream.skip;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.skip = 0;
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mstream->header_read) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(mstream->istream.skip == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen highwater_offset = mstream->istream.istream.v_offset +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.pos;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (highwater_offset >= mstream->header_size.virtual_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we want to return mixed headers and body */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t body_highwater_size = highwater_offset -
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mstream->header_size.virtual_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return read_mixed(mstream, body_highwater_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen max_buffer_size = i_stream_get_max_buffer_size(&mstream->istream.istream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mstream->hdr_buf->used >= max_buffer_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen &hdr)) > 0) {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen bool matched;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (!hdr->continued)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen mstream->cur_line++;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (hdr->eoh) {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen mstream->seen_eoh = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen matched = FALSE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mstream->header_parsed && !mstream->headers_edited) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mstream->eoh_not_matched)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen matched = !matched;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (mstream->callback != NULL) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mstream->callback(mstream, hdr, &matched,
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mstream->context);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->callbacks_called = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (matched) {
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen mstream->seen_eoh = FALSE;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen mstream->eoh_not_matched = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen continue;
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen add_eol(mstream, hdr->crlf_newline);
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen continue;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen }
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen if (hdr->continued) {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen /* Header line continued - use only the first line's
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen matched-result. Otherwise multiline headers might
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen end up being only partially picked, which wouldn't
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen be very good. However, allow callbacks to modify
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen the headers in any way they want. */
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen matched = mstream->prev_matched;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen } else if (mstream->headers_count == 0) {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen /* no include/exclude headers - default matching */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen matched = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen matched = i_bsearch(hdr->name, mstream->headers,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->headers_count,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen sizeof(*mstream->headers),
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bsearch_strcasecmp) != NULL;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->callback == NULL) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* nothing gets excluded */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (!mstream->header_parsed || mstream->headers_edited) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* first time in this line or we have actually modified
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen the header so we always want to call the callbacks */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool orig_matched = matched;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->parsed_lines = mstream->cur_line;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callback(mstream, hdr, &matched,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->context);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callbacks_called = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (matched != orig_matched &&
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen !hdr->continued && !mstream->headers_edited) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!array_is_created(&mstream->match_change_lines))
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_array_init(&mstream->match_change_lines, 8);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen array_append(&mstream->match_change_lines,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen &mstream->cur_line, 1);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (!hdr->continued) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* second time in this line. was it excluded by the
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen callback the first time? */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (match_line_changed(mstream))
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen matched = !matched;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->prev_matched = matched;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (matched == mstream->exclude) {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen /* ignore */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!hdr->continued) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen buffer_append(mstream->hdr_buf,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen hdr->name, hdr->name_len);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen buffer_append(mstream->hdr_buf,
0db4290d60bfa00774f628276d38654c56abd68cTimo Sirainen hdr->middle, hdr->middle_len);
0db4290d60bfa00774f628276d38654c56abd68cTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen buffer_append(mstream->hdr_buf,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen hdr->value, hdr->value_len);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!hdr->no_newline)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen add_eol(mstream, hdr->crlf_newline);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->skip_count >= mstream->hdr_buf->used) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* we need more */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->skip_count -= mstream->hdr_buf->used;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->skip_count > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.skip =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->skip_count;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->skip_count = 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen break;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->hdr_buf->used >= max_buffer_size)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen break;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->hdr_buf->used > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const unsigned char *data = mstream->hdr_buf->data;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->last_added_newline =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen data[mstream->hdr_buf->used-1] == '\n';
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (hdr_ret < 0) {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen if (mstream->istream.parent->stream_errno != 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.istream.stream_errno =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.parent->stream_errno;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.istream.eof =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.parent->eof;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return -1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!mstream->seen_eoh && mstream->add_missing_eoh) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool matched = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->seen_eoh = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!mstream->last_added_newline)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen add_eol(mstream, mstream->last_orig_crlf);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->header_parsed && !mstream->headers_edited) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mstream->eoh_not_matched)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen matched = !matched;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (mstream->callback != NULL) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct message_header_line fake_eoh_hdr = {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen .eoh = TRUE,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen .name = "",
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen };
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callback(mstream, &fake_eoh_hdr,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen &matched, mstream->context);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callbacks_called = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (matched) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->seen_eoh = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen add_eol(mstream, mstream->last_orig_crlf);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* don't copy eof here because we're only returning headers here.
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen the body will be returned in separate read() call. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret = hdr_stream_update_pos(mstream);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (hdr_ret == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* need more data to finish parsing headers. we may have some
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen data already available though. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (hdr == NULL) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* finished */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->hdr_ctx = NULL;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if ((!mstream->header_parsed || mstream->headers_edited ||
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callbacks_called) &&
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callback != NULL) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool matched = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callback(mstream, NULL,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen &matched, mstream->context);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* check if the callback added more headers.
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen this is allowed only if EOH wasn't added yet. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret2 = hdr_stream_update_pos(mstream);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!mstream->seen_eoh)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret += ret2;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen else {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen i_assert(ret2 == 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->header_parsed = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->header_read = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->callbacks_called = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->header_size.physical_size =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.parent->v_offset;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->header_size.virtual_size =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.istream.v_offset +
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.pos;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ret == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* we're at the end of headers. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(hdr == NULL);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(mstream->istream.istream.v_offset +
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->istream.pos ==
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->header_size.virtual_size);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return i_stream_header_filter_read(&mstream->istream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic ssize_t
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenhandle_end_body_with_lf(struct header_filter_istream *mstream, ssize_t ret)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen struct istream_private *stream = &mstream->istream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t size, last_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool last_lf;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen data = i_stream_get_data(stream->parent, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen last_offset = stream->parent->v_offset + size-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen if (mstream->last_lf_offset == last_offset)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen last_lf = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (size > 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen last_lf = data[size-1] == '\n';
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen else
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen last_lf = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == -1 && stream->parent->eof && !last_lf) {
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen /* missing LF, need to add it */
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen i_assert(!mstream->last_lf_added);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(size == 0 || data[size-1] != '\n');
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(mstream->hdr_buf, data, size);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (mstream->crlf)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen buffer_append_c(mstream->hdr_buf, '\r');
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->last_lf_offset = last_offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->last_lf_added = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->skip = 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->pos = mstream->hdr_buf->used;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->buffer = mstream->hdr_buf->data;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return mstream->crlf ? 2 : 1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->last_lf_offset = last_lf ? last_offset : (uoff_t)-1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return ret;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct header_filter_istream *mstream =
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen (struct header_filter_istream *)stream;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen uoff_t v_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ssize_t ret;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen if (mstream->last_lf_added) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->istream.eof = TRUE;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen return -1;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mstream->header_read ||
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->istream.v_offset < mstream->header_size.virtual_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = read_header(mstream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret != -2 || stream->pos != stream->skip)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (mstream->hide_body) {
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen stream->istream.eof = TRUE;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen return -1;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen }
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen v_offset = stream->parent_start_offset + stream->istream.v_offset -
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->header_size.virtual_size +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->header_size.physical_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_seek(stream->parent, v_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (mstream->end_body_with_lf)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ret = handle_end_body_with_lf(mstream, ret);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic void
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Siraineni_stream_header_filter_seek_to_header(struct header_filter_istream *mstream,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen uoff_t v_offset)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_seek(mstream->istream.parent,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.parent_start_offset);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.parent_expected_offset =
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.parent_start_offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.access_counter =
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.parent->real_stream->access_counter;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (mstream->hdr_ctx != NULL)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->skip_count = v_offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->cur_line = 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->prev_matched = FALSE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->header_read = FALSE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->seen_eoh = FALSE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->last_added_newline = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic int skip_header(struct header_filter_istream *mstream)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen size_t pos;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (mstream->header_read)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (mstream->istream.access_counter !=
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.parent->real_stream->access_counter) {
659fe5d24825b160cae512538088020d97a60239Timo Sirainen /* need to re-parse headers */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_header_filter_seek_to_header(mstream, 0);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen while (!mstream->header_read &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_read(&mstream->istream.istream) != -1) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen pos = i_stream_get_data_size(&mstream->istream.istream);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_skip(&mstream->istream.istream, pos);
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return mstream->istream.istream.stream_errno != 0 ? -1 : 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic void
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstream_reset_to(struct header_filter_istream *mstream, uoff_t v_offset)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.istream.v_offset = v_offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.skip = mstream->istream.pos = 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.buffer = NULL;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainenstatic void i_stream_header_filter_seek(struct istream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct header_filter_istream *mstream =
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen (struct header_filter_istream *)stream;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (stream->istream.v_offset == v_offset) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* just reset the input buffer */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream_reset_to(mstream, v_offset);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_seek(mstream->istream.parent,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->istream.parent_expected_offset);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* if last_lf_added=TRUE, we're currently at EOF. So reset it only if
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen we're seeking backwards, otherwise we would just add a duplicate */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mstream->last_lf_added = FALSE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (v_offset == 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* seeking to beginning of headers. */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream_reset_to(mstream, 0);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_header_filter_seek_to_header(mstream, 0);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* if we haven't parsed the whole header yet, we don't know if we
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen want to seek inside header or body. so make sure we've parsed the
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen header. */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (skip_header(mstream) < 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream_reset_to(mstream, v_offset);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (v_offset < mstream->header_size.virtual_size) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* seek into headers. we'll have to re-parse them, use
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen skip_count to set the wanted position */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_header_filter_seek_to_header(mstream, v_offset);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* body */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen v_offset += mstream->header_size.physical_size -
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mstream->header_size.virtual_size;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_seek(stream->parent,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->parent_start_offset + v_offset);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic void ATTR_NORETURN
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Siraineni_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_panic("istream-header-filter sync() not implemented");
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Siraineni_stream_header_filter_stat(struct istream_private *stream, bool exact)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct header_filter_istream *mstream =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (struct header_filter_istream *)stream;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen const struct stat *st;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen uoff_t old_offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->statbuf = *st;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (stream->statbuf.st_size == -1 || !exact)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* fix the filtered header size */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen old_offset = stream->istream.v_offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (skip_header(mstream) < 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (mstream->hide_body) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* no body */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen stream->statbuf.st_size = mstream->header_size.physical_size;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else if (!mstream->end_body_with_lf) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* no last-LF */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else if (mstream->last_lf_added) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* yes, we have added LF */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->statbuf.st_size += mstream->crlf ? 2 : 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else if (mstream->last_lf_offset != (uoff_t)-1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* no, we didn't need to add LF */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* check if we need to add LF */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_seek(stream->parent, st->st_size - 1);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (void)i_stream_read(stream->parent);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (stream->parent->stream_errno != 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen stream->istream.stream_errno =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->parent->stream_errno;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(stream->parent->eof);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ssize_t ret = handle_end_body_with_lf(mstream, -1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret > 0)
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen stream->statbuf.st_size += ret;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->statbuf.st_size -=
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (off_t)mstream->header_size.physical_size -
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (off_t)mstream->header_size.virtual_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_seek(&stream->istream, old_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#undef i_stream_create_header_filter
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct istream *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_create_header_filter(struct istream *input,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum header_filter_flags flags,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *const *headers,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen unsigned int headers_count,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen header_filter_callback *callback, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct header_filter_istream *mstream;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen unsigned int i, j;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream = i_new(struct header_filter_istream, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->pool = pool_alloconly_create(MEMPOOL_GROWING
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "header filter stream", 4096);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->headers = headers_count == 0 ? NULL :
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen p_new(mstream->pool, const char *, headers_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = j = 0; i < headers_count; i++) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ret = j == 0 ? -1 :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen strcasecmp(mstream->headers[j-1], headers[i]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* drop duplicate */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen i_assert(ret < 0);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen mstream->headers[j++] = p_strdup(mstream->pool, headers[i]);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->headers_count = j;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->hdr_buf = buffer_create_dynamic(mstream->pool, 1024);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->callback = callback;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->context = context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((flags & HEADER_FILTER_CRLF_PRESERVE) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->crlf_preserve = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if ((flags & HEADER_FILTER_NO_CR) != 0)
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen mstream->crlf = FALSE;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen else
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen mstream->crlf = TRUE;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen mstream->hide_body = (flags & HEADER_FILTER_HIDE_BODY) != 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mstream->add_missing_eoh = (flags & HEADER_FILTER_ADD_MISSING_EOH) != 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mstream->end_body_with_lf =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (flags & HEADER_FILTER_END_BODY_WITH_LF) != 0;
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen mstream->last_lf_offset = (uoff_t)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->last_added_newline = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mstream->istream.read = i_stream_header_filter_read;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen mstream->istream.seek = i_stream_header_filter_seek;
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen mstream->istream.sync = i_stream_header_filter_sync;
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen mstream->istream.stat = i_stream_header_filter_stat;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mstream->istream.istream.readable_fd = FALSE;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen mstream->istream.istream.blocking = input->blocking;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mstream->istream.istream.seekable = input->seekable;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen return i_stream_create(&mstream->istream, input, -1);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenvoid i_stream_header_filter_add(struct header_filter_istream *input,
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen const void *data, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(input->hdr_buf, data, size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen input->headers_edited = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen