istream-header-filter.c revision adb90447f6bf7b11b5fca7e87a3f256622fdef9f
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2003-2016 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "array.h"
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen#include "message-parser.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "istream-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-header-filter.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
146f9076cd456ea1e9b3f8536456d9d3c962fadbStephan Boschstruct header_filter_istream {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct istream_private istream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_t pool;
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen struct message_header_parser_ctx *hdr_ctx;
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen const char **headers;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen unsigned int headers_count;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen header_filter_callback *callback;
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen void *context;
1a5573ebc32fae2fe576ec544e1781323c1db609Timo Sirainen
1a5573ebc32fae2fe576ec544e1781323c1db609Timo Sirainen buffer_t *hdr_buf;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct message_size header_size;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen uoff_t skip_count;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen uoff_t last_lf_offset;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int cur_line, parsed_lines;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ARRAY(unsigned int) match_change_lines;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int header_read:1;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen unsigned int seen_eoh:1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int header_parsed:1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int headers_edited:1;
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen unsigned int exclude:1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int crlf:1;
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen unsigned int crlf_preserve:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int hide_body:1;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen unsigned int add_missing_eoh:1;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen unsigned int end_body_with_lf:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int last_lf_added:1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int eoh_not_matched:1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen};
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic void i_stream_header_filter_destroy(struct iostream_private *stream)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen{
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen struct header_filter_istream *mstream =
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen (struct header_filter_istream *)stream;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (mstream->hdr_ctx != NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_stream_unref(&mstream->istream.parent);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (array_is_created(&mstream->match_change_lines))
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen array_free(&mstream->match_change_lines);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen pool_unref(&mstream->pool);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic ssize_t
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainenread_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen{
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen const unsigned char *data;
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen size_t pos;
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen ssize_t ret;
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (mstream->hide_body) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mstream->istream.istream.eof = TRUE;
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen return -1;
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen }
9847ec56efa15fa063eea9988eee2d4ed9ec7d58Timo Sirainen
9847ec56efa15fa063eea9988eee2d4ed9ec7d58Timo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
9847ec56efa15fa063eea9988eee2d4ed9ec7d58Timo Sirainen if (pos <= body_highwater_size) {
d46a1e3f999dda802dc5137e883adcd7a6629cd3Timo Sirainen i_assert(pos == body_highwater_size ||
d46a1e3f999dda802dc5137e883adcd7a6629cd3Timo Sirainen (mstream->end_body_with_lf &&
d46a1e3f999dda802dc5137e883adcd7a6629cd3Timo Sirainen pos+1 == body_highwater_size));
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen ret = i_stream_read(mstream->istream.parent);
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen mstream->istream.istream.stream_errno =
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen mstream->istream.parent->stream_errno;
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen mstream->istream.istream.eof = mstream->istream.parent->eof;
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen if (ret <= 0) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen data = mstream->hdr_buf->data;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen pos = mstream->hdr_buf->used;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen i_assert(pos > 0);
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen if (mstream->end_body_with_lf && data[pos-1] != '\n' &&
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen ret == -1 && mstream->istream.istream.eof) {
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen /* add missing trailing LF to body */
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen if (mstream->crlf)
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen buffer_append_c(mstream->hdr_buf, '\r');
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen mstream->istream.buffer =
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen buffer_get_data(mstream->hdr_buf,
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen &mstream->istream.pos);
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen return mstream->hdr_buf->used - pos;
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen }
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen return ret;
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen }
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen buffer_append(mstream->hdr_buf, data + body_highwater_size,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen pos - body_highwater_size);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(ret > 0);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen mstream->istream.pos = pos;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen return ret;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic int cmp_uint(const unsigned int *i1, const unsigned int *i2)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen{
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen return *i1 < *i2 ? -1 :
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen (*i1 > *i2 ? 1 : 0);
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen}
7900eb30bac4a46b259522c58362884661483d7cJosef 'Jeff' Sipek
7900eb30bac4a46b259522c58362884661483d7cJosef 'Jeff' Sipekstatic bool match_line_changed(struct header_filter_istream *mstream)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (!array_is_created(&mstream->match_change_lines))
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return FALSE;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen return array_bsearch(&mstream->match_change_lines, &mstream->cur_line,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen cmp_uint) != NULL;
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainenstatic void add_eol(struct header_filter_istream *mstream, bool orig_crlf)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (mstream->crlf || (orig_crlf && mstream->crlf_preserve))
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen buffer_append(mstream->hdr_buf, "\r\n", 2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen}
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainenstatic ssize_t hdr_stream_update_pos(struct header_filter_istream *mstream)
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen{
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen ssize_t ret;
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen size_t pos;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainen i_assert(ret >= 0);
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen mstream->istream.pos = pos;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct message_header_line *hdr;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen uoff_t highwater_offset;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ssize_t ret, ret2;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen bool matched;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen int hdr_ret;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen if (mstream->hdr_ctx == NULL) {
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->hdr_ctx =
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen message_parse_header_init(mstream->istream.parent,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen NULL, 0);
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen }
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen /* remove skipped data from hdr_buf */
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen buffer_copy(mstream->hdr_buf, 0,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->istream.pos -= mstream->istream.skip;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->istream.skip = 0;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen if (mstream->header_read) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(mstream->istream.skip == 0);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen highwater_offset = mstream->istream.istream.v_offset +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.pos;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen if (highwater_offset >= mstream->header_size.virtual_size) {
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen /* we want to return mixed headers and body */
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen size_t body_highwater_size = highwater_offset -
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mstream->header_size.virtual_size;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return read_mixed(mstream, body_highwater_size);
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen &hdr)) > 0) {
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen mstream->cur_line++;
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen if (hdr->eoh) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen mstream->seen_eoh = TRUE;
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen matched = TRUE;
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen if (mstream->header_parsed) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (mstream->eoh_not_matched)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen matched = !matched;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen } else if (mstream->callback != NULL) {
6469cf211a57433335641725dc236ebb2b9fdd3bTimo Sirainen mstream->callback(mstream, hdr, &matched,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->context);
50c617761ee9653bd44646a95178773a3686d62eTimo Sirainen }
6cc4cce2078aca138fbce19305e69e77edcee614Timo Sirainen
bd6a8056771b6150685dea319ab5a94e021d17f1Josef 'Jeff' Sipek if (!matched) {
9f37ef2a9192e7d47e3d7ac959080fd01120f2e9Aki Tuomi mstream->seen_eoh = FALSE;
50c617761ee9653bd44646a95178773a3686d62eTimo Sirainen mstream->eoh_not_matched = TRUE;
bd6a8056771b6150685dea319ab5a94e021d17f1Josef 'Jeff' Sipek continue;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen }
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen add_eol(mstream, hdr->crlf_newline);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen continue;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen }
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen matched = mstream->headers_count == 0 ? FALSE :
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_bsearch(hdr->name, mstream->headers,
aa47c9bd1d1fc70cd699c49fd1ca92dbc7615953Timo Sirainen mstream->headers_count,
aa47c9bd1d1fc70cd699c49fd1ca92dbc7615953Timo Sirainen sizeof(*mstream->headers),
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen bsearch_strcasecmp) != NULL;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (mstream->callback == NULL) {
aa47c9bd1d1fc70cd699c49fd1ca92dbc7615953Timo Sirainen /* nothing gets excluded */
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen } else if (mstream->cur_line > mstream->parsed_lines ||
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen mstream->headers_edited) {
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen /* first time in this line or we have actually modified
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen the header so we always want to call the callbacks */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen bool orig_matched = matched;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen mstream->parsed_lines = mstream->cur_line;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen mstream->callback(mstream, hdr, &matched,
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen mstream->context);
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (matched != orig_matched &&
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen !mstream->headers_edited) {
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen if (!array_is_created(&mstream->match_change_lines))
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen i_array_init(&mstream->match_change_lines, 8);
4b41116563110d00330896a568eff1078c382827Timo Sirainen array_append(&mstream->match_change_lines,
4b41116563110d00330896a568eff1078c382827Timo Sirainen &mstream->cur_line, 1);
4b41116563110d00330896a568eff1078c382827Timo Sirainen }
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen } else {
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen /* second time in this line. was it excluded by the
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen callback the first time? */
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if (match_line_changed(mstream))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen matched = !matched;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (matched == mstream->exclude) {
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen /* ignore */
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!hdr->continued) {
dbe64f3893616a4005c8946be75d2dc8f6823d72Timo Sirainen buffer_append(mstream->hdr_buf,
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen hdr->name, hdr->name_len);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(mstream->hdr_buf,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen hdr->middle, hdr->middle_len);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen buffer_append(mstream->hdr_buf,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen hdr->value, hdr->value_len);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (!hdr->no_newline)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen add_eol(mstream, hdr->crlf_newline);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen if (mstream->skip_count >= mstream->hdr_buf->used) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen /* we need more */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mstream->skip_count -= mstream->hdr_buf->used;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen if (mstream->skip_count > 0) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mstream->istream.skip =
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen mstream->skip_count;
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen mstream->skip_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen break;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen }
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen }
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen }
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen if (hdr_ret < 0) {
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen if (mstream->istream.parent->stream_errno != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.istream.stream_errno =
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen mstream->istream.parent->stream_errno;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen mstream->istream.istream.eof =
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen mstream->istream.parent->eof;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen return -1;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen }
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen if (!mstream->seen_eoh && mstream->add_missing_eoh) {
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen mstream->seen_eoh = TRUE;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen add_eol(mstream, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* don't copy eof here because we're only returning headers here.
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen the body will be returned in separate read() call. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ret = hdr_stream_update_pos(mstream);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen if (hdr_ret == 0) {
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen /* need more data to finish parsing headers. we may have some
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen data already available though. */
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen return ret;
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen }
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen if (hdr == NULL) {
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen /* finished */
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen mstream->hdr_ctx = NULL;
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen if (!mstream->header_parsed && mstream->callback != NULL) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mstream->callback(mstream, NULL,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen &matched, mstream->context);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* check if the callback added more headers.
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen this is allowed only of EOH wasn't added yet. */
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen ret2 = hdr_stream_update_pos(mstream);
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen if (!mstream->seen_eoh)
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen ret += ret2;
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen else {
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen i_assert(ret2 == 0);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen mstream->header_parsed = TRUE;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen mstream->header_read = TRUE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mstream->header_size.physical_size =
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mstream->istream.parent->v_offset;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->header_size.virtual_size =
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->istream.istream.v_offset +
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen mstream->istream.pos;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
d938e9e4ec4c0f326dffd5ebe42c1ad893ce7e52Timo Sirainen
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen if (ret == 0) {
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen /* we're at the end of headers. */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(hdr == NULL);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen i_assert(mstream->istream.istream.v_offset +
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen mstream->istream.pos ==
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen mstream->header_size.virtual_size);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen return i_stream_header_filter_read(&mstream->istream);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen }
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen return ret;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen}
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainenstatic ssize_t
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenhandle_end_body_with_lf(struct header_filter_istream *mstream, ssize_t ret)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen struct istream_private *stream = &mstream->istream;
546335814920fb6b5b44c68c7803e654eefeae9dTimo Sirainen const unsigned char *data;
546335814920fb6b5b44c68c7803e654eefeae9dTimo Sirainen size_t size, last_offset;
546335814920fb6b5b44c68c7803e654eefeae9dTimo Sirainen bool last_lf;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen data = i_stream_get_data(stream->parent, &size);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen last_offset = stream->parent->v_offset + size-1;
eb1572d7c44ebc7b0b039d085c3dbab2ef7043ddTimo Sirainen
eb1572d7c44ebc7b0b039d085c3dbab2ef7043ddTimo Sirainen if (mstream->last_lf_offset == last_offset)
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen last_lf = TRUE;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen else if (size > 0)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen last_lf = data[size-1] == '\n';
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen else
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen last_lf = FALSE;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen if (ret == -1 && stream->parent->eof && !last_lf) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* missing LF, need to add it */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen i_assert(!mstream->last_lf_added);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen i_assert(size == 0 || data[size-1] != '\n');
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainen
382f23541ce657be87b079abd6784d376fb4eb43Timo Sirainen buffer_reset(mstream->hdr_buf);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen buffer_append(mstream->hdr_buf, data, size);
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (mstream->crlf)
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen buffer_append_c(mstream->hdr_buf, '\r');
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen mstream->last_lf_offset = last_offset;
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen mstream->last_lf_added = TRUE;
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen stream->skip = 0;
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen stream->pos = mstream->hdr_buf->used;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen stream->buffer = mstream->hdr_buf->data;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen return mstream->crlf ? 2 : 1;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen } else {
7e2671b295927b461adc8b6c4ed6a1c4761fb323Timo Sirainen mstream->last_lf_offset = last_lf ? last_offset : (uoff_t)-1;
7e2671b295927b461adc8b6c4ed6a1c4761fb323Timo Sirainen }
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen return ret;
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen}
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct header_filter_istream *mstream =
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen (struct header_filter_istream *)stream;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen uoff_t v_offset;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ssize_t ret;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if (mstream->last_lf_added) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen stream->istream.eof = TRUE;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen return -1;
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen if (!mstream->header_read ||
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen stream->istream.v_offset < mstream->header_size.virtual_size) {
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen ret = read_header(mstream);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (ret != -2 || stream->pos != stream->skip)
f90cbe597c41d5cc91debd371f8648bd8e6ffbc2Timo Sirainen return ret;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
33b469d1ca66dd2cc496d2d990b8b98e72952a29Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (mstream->hide_body) {
58ba0fe5a6904d3a65cfe268411f4cbb881234eeTimo Sirainen stream->istream.eof = TRUE;
58ba0fe5a6904d3a65cfe268411f4cbb881234eeTimo Sirainen return -1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen v_offset = stream->parent_start_offset + stream->istream.v_offset -
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen mstream->header_size.virtual_size +
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mstream->header_size.physical_size;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen i_stream_seek(stream->parent, v_offset);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen if (mstream->end_body_with_lf)
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen ret = handle_end_body_with_lf(mstream, ret);
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen return ret;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen}
b3484b5b1f47e4cf112f0e371478a2d7794b31bbTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenstatic void
d81131d3bbb4f0befb62a661d1785cf8c84a17e2Timo Siraineni_stream_header_filter_seek_to_header(struct header_filter_istream *mstream,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen uoff_t v_offset)
9456a4a3e74929f9d3d5b00b93be6d8eb69bc52aTimo Sirainen{
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen i_stream_seek(mstream->istream.parent,
4e3bcf7fdaeef92dd07a2acb1ded58422a907e87Timo Sirainen mstream->istream.parent_start_offset);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mstream->istream.parent_expected_offset =
19e161dd9e2c3a2ffc96ee8852bec0720cb30d1cTimo Sirainen mstream->istream.parent_start_offset;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mstream->istream.access_counter =
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mstream->istream.parent->real_stream->access_counter;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (mstream->hdr_ctx != NULL)
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mstream->skip_count = v_offset;
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen mstream->cur_line = 0;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mstream->header_read = FALSE;
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen mstream->seen_eoh = FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainenstatic void skip_header(struct header_filter_istream *mstream)
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen{
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen size_t pos;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (mstream->header_read)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return;
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen if (mstream->istream.access_counter !=
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mstream->istream.parent->real_stream->access_counter) {
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen /* need to re-parse headers */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_stream_header_filter_seek_to_header(mstream, 0);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen while (!mstream->header_read &&
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_stream_read(&mstream->istream.istream) != -1) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen pos = i_stream_get_data_size(&mstream->istream.istream);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_stream_skip(&mstream->istream.istream, pos);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic void
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstream_reset_to(struct header_filter_istream *mstream, uoff_t v_offset)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mstream->istream.istream.v_offset = v_offset;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mstream->istream.skip = mstream->istream.pos = 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mstream->istream.buffer = NULL;
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic void i_stream_header_filter_seek(struct istream_private *stream,
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen{
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen struct header_filter_istream *mstream =
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen (struct header_filter_istream *)stream;
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (stream->istream.v_offset == v_offset) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* just reset the input buffer */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen stream_reset_to(mstream, v_offset);
21aaa6affb9f134112b75b5db737309fc35ef1cfMartti Rannanjärvi i_stream_seek(mstream->istream.parent,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mstream->istream.parent_expected_offset);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* if last_lf_added=TRUE, we're currently at EOF. So reset it only if
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen we're seeking backwards, otherwise we would just add a duplicate */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen mstream->last_lf_added = FALSE;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if (v_offset == 0) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* seeking to beginning of headers. */
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen stream_reset_to(mstream, 0);
0206dc57f2c04da69599dea5816235cfeb2b897aMartti Rannanjärvi i_stream_header_filter_seek_to_header(mstream, 0);
0206dc57f2c04da69599dea5816235cfeb2b897aMartti Rannanjärvi return;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* if we haven't parsed the whole header yet, we don't know if we
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen want to seek inside header or body. so make sure we've parsed the
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen header. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen skip_header(mstream);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen stream_reset_to(mstream, v_offset);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (v_offset < mstream->header_size.virtual_size) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* seek into headers. we'll have to re-parse them, use
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen skip_count to set the wanted position */
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen i_stream_header_filter_seek_to_header(mstream, v_offset);
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen } else {
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen /* body */
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen v_offset += mstream->header_size.physical_size -
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen mstream->header_size.virtual_size;
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen i_stream_seek(stream->parent,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen stream->parent_start_offset + v_offset);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen }
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen}
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainenstatic void ATTR_NORETURN
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Siraineni_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED)
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen{
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen i_panic("istream-header-filter sync() not implemented");
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen}
2c8ca7e88ec881c473fb90e5f647c1f563877164Timo Sirainen
2c8ca7e88ec881c473fb90e5f647c1f563877164Timo Sirainenstatic int
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Siraineni_stream_header_filter_stat(struct istream_private *stream, bool exact)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct header_filter_istream *mstream =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (struct header_filter_istream *)stream;
e4c90f0b88e40a8f92b8f5e1f1a3ea701e5c965cTimo Sirainen const struct stat *st;
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen uoff_t old_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return -1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen stream->statbuf = *st;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen if (stream->statbuf.st_size == -1 || !exact)
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen return 0;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen /* fix the filtered header size */
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen old_offset = stream->istream.v_offset;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen skip_header(mstream);
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen stream->statbuf.st_size -=
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen (off_t)mstream->header_size.physical_size -
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen (off_t)mstream->header_size.virtual_size;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen i_stream_seek(&stream->istream, old_offset);
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen return 0;
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen}
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen#undef i_stream_create_header_filter
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainenstruct istream *
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Siraineni_stream_create_header_filter(struct istream *input,
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen enum header_filter_flags flags,
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen const char *const *headers,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int headers_count,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen header_filter_callback *callback, void *context)
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen{
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen struct header_filter_istream *mstream;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen unsigned int i, j;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen int ret;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen
50c617761ee9653bd44646a95178773a3686d62eTimo Sirainen mstream = i_new(struct header_filter_istream, 1);
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen mstream->pool = pool_alloconly_create(MEMPOOL_GROWING
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen "header filter stream", 4096);
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen mstream->headers = headers_count == 0 ? NULL :
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen p_new(mstream->pool, const char *, headers_count);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen for (i = j = 0; i < headers_count; i++) {
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen ret = j == 0 ? -1 :
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen strcasecmp(mstream->headers[j-1], headers[i]);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (ret == 0) {
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen /* drop duplicate */
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen continue;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen i_assert(ret < 0);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mstream->headers[j++] = p_strdup(mstream->pool, headers[i]);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen mstream->headers_count = j;
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen mstream->hdr_buf = buffer_create_dynamic(mstream->pool, 1024);
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen mstream->callback = callback;
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen mstream->context = context;
e2d268e9531227ead6a98466ecf3c046c857ef70Timo Sirainen mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0;
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen if ((flags & HEADER_FILTER_CRLF_PRESERVE) != 0)
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen mstream->crlf_preserve = TRUE;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen else if ((flags & HEADER_FILTER_NO_CR) != 0)
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen mstream->crlf = FALSE;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen else
900bb5e316d030cdebff7ee128ce65881dfb27f7Timo Sirainen mstream->crlf = TRUE;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mstream->hide_body = (flags & HEADER_FILTER_HIDE_BODY) != 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mstream->add_missing_eoh = (flags & HEADER_FILTER_ADD_MISSING_EOH) != 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mstream->end_body_with_lf =
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (flags & HEADER_FILTER_END_BODY_WITH_LF) != 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.read = i_stream_header_filter_read;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mstream->istream.seek = i_stream_header_filter_seek;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mstream->istream.sync = i_stream_header_filter_sync;
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen mstream->istream.stat = i_stream_header_filter_stat;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen mstream->istream.istream.readable_fd = FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mstream->istream.istream.blocking = input->blocking;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mstream->istream.istream.seekable = input->seekable;
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen return i_stream_create(&mstream->istream, input, -1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenvoid i_stream_header_filter_add(struct header_filter_istream *input,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen const void *data, size_t size)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen buffer_append(input->hdr_buf, data, size);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen input->headers_edited = TRUE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen