istream-header-filter.c revision 71ecc97593a25c2444316b74e5882e6ce0a82c0c
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2003-2016 Dovecot authors, see the included COPYING file */
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen const char **headers;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenstatic void i_stream_header_filter_destroy(struct iostream_private *stream)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (array_is_created(&mstream->match_change_lines))
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenread_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen const unsigned char *data;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->istream.istream.eof = mstream->istream.parent->eof;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (mstream->end_body_with_lf && data[pos-1] != '\n' &&
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen /* add missing trailing LF to body */
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->istream.buffer = mstream->hdr_buf->data;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->istream.pos = mstream->hdr_buf->used;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen buffer_append(mstream->hdr_buf, data + body_highwater_size,
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenstatic int cmp_uint(const unsigned int *i1, const unsigned int *i2)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenstatic bool match_line_changed(struct header_filter_istream *mstream)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (!array_is_created(&mstream->match_change_lines))
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen return array_bsearch(&mstream->match_change_lines, &mstream->cur_line,
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenstatic void add_eol(struct header_filter_istream *mstream, bool orig_crlf)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (mstream->crlf || (orig_crlf && mstream->crlf_preserve))
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainenstatic ssize_t hdr_stream_update_pos(struct header_filter_istream *mstream)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
ddd1adf19cacc6186fbc713d255e1e82086d7751Timo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen message_parse_header_init(mstream->istream.parent,
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen /* remove skipped data from hdr_buf */
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen mstream->istream.pos -= mstream->istream.skip;
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen highwater_offset = mstream->istream.istream.v_offset +
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (highwater_offset >= mstream->header_size.virtual_size) {
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen /* we want to return mixed headers and body */
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen size_t body_highwater_size = highwater_offset -
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen return read_mixed(mstream, body_highwater_size);
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (mstream->hdr_buf->used >= mstream->istream.max_buffer_size)
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen if (mstream->header_parsed && !mstream->headers_edited) {
ddd1adf19cacc6186fbc713d255e1e82086d7751Timo Sirainen /* Header line continued - use only the first line's
ddd1adf19cacc6186fbc713d255e1e82086d7751Timo Sirainen matched-result. Otherwise multiline headers might
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen end up being only partially picked, which wouldn't
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen be very good. However, allow callbacks to modify
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen the headers in any way they want. */
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen /* no include/exclude headers - default matching */
ddd1adf19cacc6186fbc713d255e1e82086d7751Timo Sirainen matched = i_bsearch(hdr->name, mstream->headers,
ddd1adf19cacc6186fbc713d255e1e82086d7751Timo Sirainen /* nothing gets excluded */
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen } else if (!mstream->header_parsed || mstream->headers_edited) {
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen /* first time in this line or we have actually modified
37bd98570b30513255a19cc52de16594bc4256e0Timo Sirainen the header so we always want to call the callbacks */
if (hdr_ret < 0) {
if (hdr_ret == 0) {
return ret;
if (ret == 0) {
return ret;
static ssize_t
const unsigned char *data;
bool last_lf;
else if (size > 0)
return ret;
return ret;
return ret;
if (v_offset == 0) {
static void ATTR_NORETURN
if (ret > 0)
struct istream *
const char *const *headers,
unsigned int headers_count,
int ret;
for (i = j = 0; i < headers_count; i++) {
if (ret == 0) {