bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen#include "lib.h"
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen#include "array.h"
6e2856a5beeeb0edf5d852dde63d99fb9af11151Martti Rannanjärvi#include "sort.h"
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen#include "message-parser.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream-private.h"
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen#include "istream-header-filter.h"
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
b82e145e384466f60dda7e349505e1092938345fTimo Sirainenstruct header_filter_istream {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private istream;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen pool_t pool;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen struct message_header_parser_ctx *hdr_ctx;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen const char **headers;
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen unsigned int headers_count;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen header_filter_callback *callback;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen void *context;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_t *hdr_buf;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen struct message_size header_size;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen uoff_t skip_count;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen uoff_t last_lf_offset;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen unsigned int cur_line, parsed_lines;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(unsigned int) match_change_lines;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool header_read:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool seen_eoh:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool header_parsed:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool headers_edited:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool exclude:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool crlf:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool crlf_preserve:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool hide_body:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool add_missing_eoh:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool end_body_with_lf:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool last_lf_added:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool last_orig_crlf:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool last_added_newline:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool eoh_not_matched:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool callbacks_called:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool prev_matched:1;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen};
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
11b7d7a86d6e6d945ade461c5b1280b8a0825f61Timo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream);
11b7d7a86d6e6d945ade461c5b1280b8a0825f61Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void i_stream_header_filter_destroy(struct iostream_private *stream)
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen{
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen struct header_filter_istream *mstream =
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen (struct header_filter_istream *)stream;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (mstream->hdr_ctx != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen if (array_is_created(&mstream->match_change_lines))
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen array_free(&mstream->match_change_lines);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&mstream->pool);
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen}
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainenstatic ssize_t
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainenread_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen{
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen const unsigned char *data;
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen size_t pos;
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen ssize_t ret;
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen
b4ddf7020a7daccd96dd239cf93207e7423c8cfeTimo Sirainen if (mstream->hide_body) {
b4ddf7020a7daccd96dd239cf93207e7423c8cfeTimo Sirainen mstream->istream.istream.eof = TRUE;
b4ddf7020a7daccd96dd239cf93207e7423c8cfeTimo Sirainen return -1;
b4ddf7020a7daccd96dd239cf93207e7423c8cfeTimo Sirainen }
b4ddf7020a7daccd96dd239cf93207e7423c8cfeTimo Sirainen
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (pos <= body_highwater_size) {
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen i_assert(pos == body_highwater_size ||
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen (mstream->end_body_with_lf &&
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen pos+1 == body_highwater_size));
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen ret = i_stream_read_memarea(mstream->istream.parent);
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen mstream->istream.istream.stream_errno =
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen mstream->istream.parent->stream_errno;
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen mstream->istream.istream.eof = mstream->istream.parent->eof;
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (ret <= 0) {
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen data = mstream->hdr_buf->data;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen pos = mstream->hdr_buf->used;
1358f8214581ea353e306083dc096772f3d0f185Timo Sirainen i_assert(pos > 0);
1358f8214581ea353e306083dc096772f3d0f185Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (mstream->end_body_with_lf && data[pos-1] != '\n' &&
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen ret == -1 && mstream->istream.istream.eof) {
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen /* add missing trailing LF to body */
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (mstream->crlf)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen buffer_append_c(mstream->hdr_buf, '\r');
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen mstream->istream.buffer = mstream->hdr_buf->data;
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen mstream->istream.pos = mstream->hdr_buf->used;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen return mstream->hdr_buf->used - pos;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen }
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen return ret;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen }
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen }
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen buffer_append(mstream->hdr_buf, data + body_highwater_size,
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen pos - body_highwater_size);
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(ret > 0);
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen mstream->istream.pos = pos;
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen return ret;
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen}
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenstatic int cmp_uint(const unsigned int *i1, const unsigned int *i2)
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen{
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen return *i1 < *i2 ? -1 :
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen (*i1 > *i2 ? 1 : 0);
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen}
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainenstatic bool match_line_changed(struct header_filter_istream *mstream)
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen{
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen if (!array_is_created(&mstream->match_change_lines))
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen return FALSE;
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen return array_bsearch(&mstream->match_change_lines, &mstream->cur_line,
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen cmp_uint) != NULL;
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen}
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainenstatic void add_eol(struct header_filter_istream *mstream, bool orig_crlf)
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen{
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen if (mstream->crlf || (orig_crlf && mstream->crlf_preserve))
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen buffer_append(mstream->hdr_buf, "\r\n", 2);
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen else
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen mstream->last_orig_crlf = orig_crlf;
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen mstream->last_added_newline = TRUE;
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen}
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainenstatic ssize_t hdr_stream_update_pos(struct header_filter_istream *mstream)
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen{
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen ssize_t ret;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen size_t pos;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen i_assert(ret >= 0);
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen mstream->istream.pos = pos;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen return ret;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen}
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen{
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen struct message_header_line *hdr;
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen uoff_t highwater_offset;
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen size_t max_buffer_size;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen ssize_t ret, ret2;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int hdr_ret;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (mstream->hdr_ctx == NULL) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->hdr_ctx =
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen message_parse_header_init(mstream->istream.parent,
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen NULL, 0);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen /* remove skipped data from hdr_buf */
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_copy(mstream->hdr_buf, 0,
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->istream.pos -= mstream->istream.skip;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->istream.skip = 0;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen if (mstream->header_read) {
8406c1d3e6c4fbb3df9f6eab0921c47e7f804bc9Timo Sirainen i_assert(mstream->istream.skip == 0);
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen highwater_offset = mstream->istream.istream.v_offset +
8406c1d3e6c4fbb3df9f6eab0921c47e7f804bc9Timo Sirainen mstream->istream.pos;
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen if (highwater_offset >= mstream->header_size.virtual_size) {
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen /* we want to return mixed headers and body */
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen size_t body_highwater_size = highwater_offset -
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen mstream->header_size.virtual_size;
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen return read_mixed(mstream, body_highwater_size);
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen }
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen }
c2afdbf963d0564a542d71ca784deb0c2f7776d0Timo Sirainen
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen max_buffer_size = i_stream_get_max_buffer_size(&mstream->istream.istream);
fdf15b2c4fd47078108f556a58c6b9f365449f9eTimo Sirainen if (mstream->hdr_buf->used >= max_buffer_size) {
fdf15b2c4fd47078108f556a58c6b9f365449f9eTimo Sirainen i_assert(max_buffer_size > 0);
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen return -2;
fdf15b2c4fd47078108f556a58c6b9f365449f9eTimo Sirainen }
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen
5a2917dd7248d61c540dd310627a781934ba5334Timo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
5a2917dd7248d61c540dd310627a781934ba5334Timo Sirainen &hdr)) > 0) {
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen bool matched;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen if (!hdr->continued)
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen mstream->cur_line++;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (hdr->eoh) {
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen mstream->seen_eoh = TRUE;
44ef49403ac7bddac84a1e322d170ed53cd37c95Timo Sirainen matched = FALSE;
bf5682ed5399fce13b2053e20098e2de19751c59Timo Sirainen if (mstream->header_parsed && !mstream->headers_edited) {
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen if (mstream->eoh_not_matched)
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen matched = !matched;
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen } else if (mstream->callback != NULL) {
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen mstream->callback(mstream, hdr, &matched,
5c19ab0eb3900ebf59b7839594026c275168e2b8Timo Sirainen mstream->context);
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen mstream->callbacks_called = TRUE;
5c19ab0eb3900ebf59b7839594026c275168e2b8Timo Sirainen }
5c19ab0eb3900ebf59b7839594026c275168e2b8Timo Sirainen
44ef49403ac7bddac84a1e322d170ed53cd37c95Timo Sirainen if (matched) {
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen mstream->seen_eoh = FALSE;
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen mstream->eoh_not_matched = TRUE;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen continue;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen }
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen add_eol(mstream, hdr->crlf_newline);
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen continue;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen if (hdr->continued) {
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen /* Header line continued - use only the first line's
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen matched-result. Otherwise multiline headers might
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen end up being only partially picked, which wouldn't
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen be very good. However, allow callbacks to modify
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen the headers in any way they want. */
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen matched = mstream->prev_matched;
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen } else if (mstream->headers_count == 0) {
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen /* no include/exclude headers - default matching */
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen matched = FALSE;
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen } else {
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen matched = i_bsearch(hdr->name, mstream->headers,
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen mstream->headers_count,
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen sizeof(*mstream->headers),
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen bsearch_strcasecmp) != NULL;
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen }
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen if (mstream->callback == NULL) {
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen /* nothing gets excluded */
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen } else if (!mstream->header_parsed || mstream->headers_edited) {
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen /* first time in this line or we have actually modified
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen the header so we always want to call the callbacks */
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen bool orig_matched = matched;
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen mstream->parsed_lines = mstream->cur_line;
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen mstream->callback(mstream, hdr, &matched,
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen mstream->context);
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen mstream->callbacks_called = TRUE;
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen if (matched != orig_matched &&
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen !hdr->continued && !mstream->headers_edited) {
0989e8ba44ec35dc9322e424b5213b96596319e7Timo Sirainen if (!array_is_created(&mstream->match_change_lines))
0989e8ba44ec35dc9322e424b5213b96596319e7Timo Sirainen i_array_init(&mstream->match_change_lines, 8);
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen array_append(&mstream->match_change_lines,
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen &mstream->cur_line, 1);
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen }
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen } else if (!hdr->continued) {
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen /* second time in this line. was it excluded by the
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen callback the first time? */
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen if (match_line_changed(mstream))
e59cc428c2e2233adedba549a556b83a01ce809eTimo Sirainen matched = !matched;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen mstream->prev_matched = matched;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen if (matched == mstream->exclude) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen /* ignore */
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen } else {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (!hdr->continued) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_append(mstream->hdr_buf,
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen hdr->name, hdr->name_len);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_append(mstream->hdr_buf,
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen hdr->middle, hdr->middle_len);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_append(mstream->hdr_buf,
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen hdr->value, hdr->value_len);
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen if (!hdr->no_newline)
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen add_eol(mstream, hdr->crlf_newline);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (mstream->skip_count >= mstream->hdr_buf->used) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen /* we need more */
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->skip_count -= mstream->hdr_buf->used;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen } else {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (mstream->skip_count > 0) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->istream.skip =
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->skip_count;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->skip_count = 0;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen break;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen if (mstream->hdr_buf->used >= max_buffer_size)
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen break;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen if (mstream->hdr_buf->used > 0) {
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen const unsigned char *data = mstream->hdr_buf->data;
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen mstream->last_added_newline =
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen data[mstream->hdr_buf->used-1] == '\n';
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen if (hdr_ret < 0) {
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen if (mstream->istream.parent->stream_errno != 0) {
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen mstream->istream.istream.stream_errno =
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen mstream->istream.parent->stream_errno;
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen mstream->istream.istream.eof =
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen mstream->istream.parent->eof;
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen return -1;
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen }
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen if (!mstream->seen_eoh && mstream->add_missing_eoh) {
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek bool matched = FALSE;
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen mstream->seen_eoh = TRUE;
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen if (!mstream->last_added_newline)
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen add_eol(mstream, mstream->last_orig_crlf);
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen if (mstream->header_parsed && !mstream->headers_edited) {
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen if (mstream->eoh_not_matched)
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen matched = !matched;
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen } else if (mstream->callback != NULL) {
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek struct message_header_line fake_eoh_hdr = {
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek .eoh = TRUE,
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek .name = "",
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek };
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek mstream->callback(mstream, &fake_eoh_hdr,
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek &matched, mstream->context);
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek mstream->callbacks_called = TRUE;
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek }
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek if (matched) {
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek mstream->seen_eoh = FALSE;
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek } else {
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek add_eol(mstream, mstream->last_orig_crlf);
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek }
3b5028747f195bca08751015e5b5a28cd5f4f8d4Timo Sirainen }
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen }
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen
395458c963dbf061a8cc167646e01d564bb92050Timo Sirainen /* don't copy eof here because we're only returning headers here.
395458c963dbf061a8cc167646e01d564bb92050Timo Sirainen the body will be returned in separate read() call. */
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen ret = hdr_stream_update_pos(mstream);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (hdr_ret == 0) {
acbb7e67acebcda7ed12eb3e0e02e1d799f24e3aTimo Sirainen /* need more data to finish parsing headers. we may have some
acbb7e67acebcda7ed12eb3e0e02e1d799f24e3aTimo Sirainen data already available though. */
5a2917dd7248d61c540dd310627a781934ba5334Timo Sirainen return ret;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
5a2917dd7248d61c540dd310627a781934ba5334Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (hdr == NULL) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen /* finished */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
395627417d97abb7adf1ab987b992e4ebee6ab65Timo Sirainen mstream->hdr_ctx = NULL;
395627417d97abb7adf1ab987b992e4ebee6ab65Timo Sirainen
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen if ((!mstream->header_parsed || mstream->headers_edited ||
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen mstream->callbacks_called) &&
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen mstream->callback != NULL) {
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen bool matched = FALSE;
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen mstream->callback(mstream, NULL,
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen &matched, mstream->context);
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen /* check if the callback added more headers.
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen this is allowed only if EOH wasn't added yet. */
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen ret2 = hdr_stream_update_pos(mstream);
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen if (!mstream->seen_eoh)
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen ret += ret2;
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen else {
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen i_assert(ret2 == 0);
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen }
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen }
922ab71017974de1e949ff3f0da47eebbf8b88d9Timo Sirainen mstream->header_parsed = TRUE;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->header_read = TRUE;
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen mstream->callbacks_called = FALSE;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen mstream->header_size.physical_size =
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen mstream->istream.parent->v_offset;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->header_size.virtual_size =
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen mstream->istream.istream.v_offset +
3c07b1481e4e1c2de64a3ae3c07bc7ac6d9def65Timo Sirainen mstream->istream.pos;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (ret == 0) {
b335d3864f1134a100be84105d4c56be161da4d0Timo Sirainen /* we're at the end of headers. */
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen i_assert(hdr == NULL);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen i_assert(mstream->istream.istream.v_offset +
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->istream.pos ==
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->header_size.virtual_size);
b335d3864f1134a100be84105d4c56be161da4d0Timo Sirainen
11b7d7a86d6e6d945ade461c5b1280b8a0825f61Timo Sirainen return i_stream_header_filter_read(&mstream->istream);
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen return ret;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen}
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainenstatic ssize_t
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainenhandle_end_body_with_lf(struct header_filter_istream *mstream, ssize_t ret)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen{
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen struct istream_private *stream = &mstream->istream;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen const unsigned char *data;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen size_t size, last_offset;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen bool last_lf;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen data = i_stream_get_data(stream->parent, &size);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen last_offset = stream->parent->v_offset + size-1;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (mstream->last_lf_offset == last_offset)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen last_lf = TRUE;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen else if (size > 0)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen last_lf = data[size-1] == '\n';
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen else
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen last_lf = FALSE;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (ret == -1 && stream->parent->eof && !last_lf) {
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen /* missing LF, need to add it */
33a8963217d05d0a36739c59dfc71bd0c51d6f67Timo Sirainen i_assert(!mstream->last_lf_added);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen i_assert(size == 0 || data[size-1] != '\n');
33a8963217d05d0a36739c59dfc71bd0c51d6f67Timo Sirainen
f6d5c9fbdac9af5c4d3f467f828dc6f056309d5eTimo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen buffer_append(mstream->hdr_buf, data, size);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (mstream->crlf)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen buffer_append_c(mstream->hdr_buf, '\r');
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen mstream->last_lf_offset = last_offset;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen mstream->last_lf_added = TRUE;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen stream->skip = 0;
33a8963217d05d0a36739c59dfc71bd0c51d6f67Timo Sirainen stream->pos = mstream->hdr_buf->used;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen stream->buffer = mstream->hdr_buf->data;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen return mstream->crlf ? 2 : 1;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen } else {
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen mstream->last_lf_offset = last_lf ? last_offset : (uoff_t)-1;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen }
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen return ret;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen}
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream)
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen{
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen struct header_filter_istream *mstream =
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen (struct header_filter_istream *)stream;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen uoff_t v_offset;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen ssize_t ret;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (mstream->last_lf_added) {
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen stream->istream.eof = TRUE;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen return -1;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen }
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen if (!mstream->header_read ||
fdf15b2c4fd47078108f556a58c6b9f365449f9eTimo Sirainen stream->istream.v_offset < mstream->header_size.virtual_size)
fdf15b2c4fd47078108f556a58c6b9f365449f9eTimo Sirainen return read_header(mstream);
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen if (mstream->hide_body) {
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen stream->istream.eof = TRUE;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen return -1;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen }
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen v_offset = stream->parent_start_offset + stream->istream.v_offset -
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->header_size.virtual_size +
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->header_size.physical_size;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_seek(stream->parent, v_offset);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen if (mstream->end_body_with_lf)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen ret = handle_end_body_with_lf(mstream, ret);
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen return ret;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen}
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void
4334b9b032298defd4d3906f5357698ff016ead0Timo Siraineni_stream_header_filter_seek_to_header(struct header_filter_istream *mstream,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen uoff_t v_offset)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_seek(mstream->istream.parent,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.parent_start_offset);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.parent_expected_offset =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.parent_start_offset;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.access_counter =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.parent->real_stream->access_counter;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (mstream->hdr_ctx != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->skip_count = v_offset;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->cur_line = 0;
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen mstream->prev_matched = FALSE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->header_read = FALSE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->seen_eoh = FALSE;
5695ec03a0cc4836896e46a01bb9336782aee326Timo Sirainen mstream->last_added_newline = TRUE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainenstatic int skip_header(struct header_filter_istream *mstream)
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen{
256079fb2c9b401141aca3d53046ce8afa7265f6Timo Sirainen size_t pos;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (mstream->header_read)
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainen return 0;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (mstream->istream.access_counter !=
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.parent->real_stream->access_counter) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* need to re-parse headers */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_header_filter_seek_to_header(mstream, 0);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
32efbf50df2b04859fd9d568c52ca62c4e21a4fbTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen while (!mstream->header_read &&
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen i_stream_read_memarea(&mstream->istream.istream) != -1) {
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen pos = i_stream_get_data_size(&mstream->istream.istream);
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen i_stream_skip(&mstream->istream.istream, pos);
32efbf50df2b04859fd9d568c52ca62c4e21a4fbTimo Sirainen }
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainen return mstream->istream.istream.stream_errno != 0 ? -1 : 0;
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen}
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstream_reset_to(struct header_filter_istream *mstream, uoff_t v_offset)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.istream.v_offset = v_offset;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.skip = mstream->istream.pos = 0;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mstream->istream.buffer = NULL;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void i_stream_header_filter_seek(struct istream_private *stream,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen{
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen struct header_filter_istream *mstream =
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen (struct header_filter_istream *)stream;
32efbf50df2b04859fd9d568c52ca62c4e21a4fbTimo Sirainen
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen if (stream->istream.v_offset == v_offset) {
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen /* just reset the input buffer */
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen stream_reset_to(mstream, v_offset);
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen i_stream_seek(mstream->istream.parent,
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen mstream->istream.parent_expected_offset);
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen return;
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen }
33a8963217d05d0a36739c59dfc71bd0c51d6f67Timo Sirainen /* if last_lf_added=TRUE, we're currently at EOF. So reset it only if
33a8963217d05d0a36739c59dfc71bd0c51d6f67Timo Sirainen we're seeking backwards, otherwise we would just add a duplicate */
33a8963217d05d0a36739c59dfc71bd0c51d6f67Timo Sirainen mstream->last_lf_added = FALSE;
9a1a2583687a5bd9d47bdfd435c78b46ca5d5af6Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (v_offset == 0) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* seeking to beginning of headers. */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream_reset_to(mstream, 0);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_header_filter_seek_to_header(mstream, 0);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen }
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* if we haven't parsed the whole header yet, we don't know if we
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen want to seek inside header or body. so make sure we've parsed the
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen header. */
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainen if (skip_header(mstream) < 0)
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainen return;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream_reset_to(mstream, v_offset);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen if (v_offset < mstream->header_size.virtual_size) {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen /* seek into headers. we'll have to re-parse them, use
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen skip_count to set the wanted position */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_header_filter_seek_to_header(mstream, v_offset);
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen } else {
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen /* body */
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen v_offset += mstream->header_size.physical_size -
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen mstream->header_size.virtual_size;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen i_stream_seek(stream->parent,
9511a40d933181045343110c8101b75887062aaeTimo Sirainen stream->parent_start_offset + v_offset);
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen }
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen}
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenstatic void ATTR_NORETURN
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen i_panic("istream-header-filter sync() not implemented");
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenstatic int
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_header_filter_stat(struct istream_private *stream, bool exact)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen struct header_filter_istream *mstream =
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen (struct header_filter_istream *)stream;
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen const struct stat *st;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen uoff_t old_offset;
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen stream->statbuf = *st;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (stream->statbuf.st_size == -1 || !exact)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen /* fix the filtered header size */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen old_offset = stream->istream.v_offset;
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainen if (skip_header(mstream) < 0)
2739e568eb2f33f6219d97261c94e67b68da2794Timo Sirainen return -1;
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen if (mstream->hide_body) {
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen /* no body */
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen stream->statbuf.st_size = mstream->header_size.physical_size;
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen } else if (!mstream->end_body_with_lf) {
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen /* no last-LF */
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen } else if (mstream->last_lf_added) {
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen /* yes, we have added LF */
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen stream->statbuf.st_size += mstream->crlf ? 2 : 1;
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen } else if (mstream->last_lf_offset != (uoff_t)-1) {
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen /* no, we didn't need to add LF */
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen } else {
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen /* check if we need to add LF */
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen i_stream_seek(stream->parent, st->st_size - 1);
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen (void)i_stream_read_memarea(stream->parent);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen if (stream->parent->stream_errno != 0) {
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen stream->istream.stream_errno =
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen stream->parent->stream_errno;
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen return -1;
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen }
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen i_assert(stream->parent->eof);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen ssize_t ret = handle_end_body_with_lf(mstream, -1);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen if (ret > 0)
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen stream->statbuf.st_size += ret;
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen }
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen stream->statbuf.st_size -=
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen (off_t)mstream->header_size.physical_size -
fff56e138fc28fd6fa141122ac768162d6f7e4d1Timo Sirainen (off_t)mstream->header_size.virtual_size;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_seek(&stream->istream, old_offset);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef i_stream_create_header_filter
b82e145e384466f60dda7e349505e1092938345fTimo Sirainenstruct istream *
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Siraineni_stream_create_header_filter(struct istream *input,
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen enum header_filter_flags flags,
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen const char *const *headers,
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen unsigned int headers_count,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen header_filter_callback *callback, void *context)
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen{
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen struct header_filter_istream *mstream;
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen unsigned int i, j;
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen int ret;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen mstream = i_new(struct header_filter_istream, 1);
221351ed85c839e0b03d82c47654c3d17202e3dbTimo Sirainen mstream->pool = pool_alloconly_create(MEMPOOL_GROWING
221351ed85c839e0b03d82c47654c3d17202e3dbTimo Sirainen "header filter stream", 4096);
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen
7122ddeac635cdc896ecc8093dad2e942115a98aTimo Sirainen mstream->headers = headers_count == 0 ? NULL :
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen p_new(mstream->pool, const char *, headers_count);
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen for (i = j = 0; i < headers_count; i++) {
b2b2b63e233f66aa7c115217a876cf3310baa107Timo Sirainen ret = j == 0 ? -1 :
b2b2b63e233f66aa7c115217a876cf3310baa107Timo Sirainen strcasecmp(mstream->headers[j-1], headers[i]);
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen if (ret == 0) {
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen /* drop duplicate */
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen continue;
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen }
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen i_assert(ret < 0);
b32c01699fa9cb0f3ceb73e3618d762b36f2428fTimo Sirainen mstream->headers[j++] = p_strdup(mstream->pool, headers[i]);
701a594c661ee65ce822e3494ee36a4369f62a71Timo Sirainen }
aee9abea526bc220c174d39af9e320f5487527daTimo Sirainen mstream->headers_count = j;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen mstream->hdr_buf = buffer_create_dynamic(mstream->pool, 1024);
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->callback = callback;
a72355fef49c512c13b7d8c3e07f4f76ebd57a10Timo Sirainen mstream->context = context;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0;
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen if ((flags & HEADER_FILTER_CRLF_PRESERVE) != 0)
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen mstream->crlf_preserve = TRUE;
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen else if ((flags & HEADER_FILTER_NO_CR) != 0)
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen mstream->crlf = FALSE;
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen else
3818c2a96699d09f65b880df6e7962570a387eacTimo Sirainen mstream->crlf = TRUE;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen mstream->hide_body = (flags & HEADER_FILTER_HIDE_BODY) != 0;
aeed83649fbeef2cba51fd909635c4463ee642e7Timo Sirainen mstream->add_missing_eoh = (flags & HEADER_FILTER_ADD_MISSING_EOH) != 0;
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen mstream->end_body_with_lf =
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen (flags & HEADER_FILTER_END_BODY_WITH_LF) != 0;
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen mstream->last_lf_offset = (uoff_t)-1;
5695ec03a0cc4836896e46a01bb9336782aee326Timo Sirainen mstream->last_added_newline = TRUE;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen mstream->istream.read = i_stream_header_filter_read;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen mstream->istream.seek = i_stream_header_filter_seek;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen mstream->istream.sync = i_stream_header_filter_sync;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen mstream->istream.stat = i_stream_header_filter_stat;
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen mstream->istream.istream.readable_fd = FALSE;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen mstream->istream.istream.blocking = input->blocking;
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen mstream->istream.istream.seekable = input->seekable;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen return i_stream_create(&mstream->istream, input, -1, 0);
b82e145e384466f60dda7e349505e1092938345fTimo Sirainen}
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainenvoid i_stream_header_filter_add(struct header_filter_istream *input,
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen const void *data, size_t size)
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen{
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen buffer_append(input->hdr_buf, data, size);
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen input->headers_edited = TRUE;
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainen}