istream-header-filter.c revision 221351ed85c839e0b03d82c47654c3d17202e3db
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "lib.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "array.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "message-parser.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "istream-internal.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "istream-header-filter.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include <stdlib.h>
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstruct header_filter_istream {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct istream_private istream;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen pool_t pool;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen struct message_header_parser_ctx *hdr_ctx;
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen const char **headers;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int headers_count;
40a5aeebf6b4858b93f0ddff0bf12fba769cf903Timo Sirainen
40a5aeebf6b4858b93f0ddff0bf12fba769cf903Timo Sirainen header_filter_callback *callback;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen void *context;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen buffer_t *hdr_buf;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen struct message_size header_size;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen uoff_t skip_count;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen unsigned int cur_line, parsed_lines;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen ARRAY_DEFINE(match_change_lines, unsigned int);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen unsigned int header_read:1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen unsigned int header_parsed:1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen unsigned int exclude:1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen unsigned int crlf:1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen unsigned int hide_body:1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen};
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic void i_stream_header_filter_destroy(struct iostream_private *stream)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen struct header_filter_istream *mstream =
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen (struct header_filter_istream *)stream;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (mstream->hdr_ctx != NULL)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen i_stream_unref(&mstream->istream.parent);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (array_is_created(&mstream->match_change_lines))
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen array_free(&mstream->match_change_lines);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen pool_unref(&mstream->pool);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Siraineni_stream_header_filter_set_max_buffer_size(struct iostream_private *stream,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen size_t max_size)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct header_filter_istream *mstream =
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (struct header_filter_istream *)stream;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.max_buffer_size = max_size;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_set_max_buffer_size(mstream->istream.parent, max_size);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic ssize_t
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenread_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const unsigned char *data;
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen size_t pos;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ssize_t ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->hide_body) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.istream.eof = TRUE;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return -1;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (pos == body_highwater_size) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ret = i_stream_read(mstream->istream.parent);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.istream.stream_errno =
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.parent->stream_errno;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.istream.eof = mstream->istream.parent->eof;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ret <= 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return ret;
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen }
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen i_assert(pos > body_highwater_size);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen buffer_append(mstream->hdr_buf, data + body_highwater_size,
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen pos - body_highwater_size);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->istream.pos = pos;
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen return ret;
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainenstatic int cmp_uint(const void *p1, const void *p2)
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const unsigned int *i1 = p1, *i2 = p2;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return *i1 < *i2 ? -1 :
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen (*i1 > *i2 ? 1 : 0);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic bool match_line_changed(struct header_filter_istream *mstream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const unsigned int *lines;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int count;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!array_is_created(&mstream->match_change_lines))
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return FALSE;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen lines = array_get(&mstream->match_change_lines, &count);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return bsearch(&mstream->cur_line, lines, count, sizeof(*lines),
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen cmp_uint) != NULL;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct message_header_line *hdr;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen uoff_t highwater_offset;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen size_t pos;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ssize_t ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen bool matched;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen int hdr_ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->hdr_ctx == NULL) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->hdr_ctx =
b8864211b88ed7521e9af514590639344af38910Timo Sirainen message_parse_header_init(mstream->istream.parent,
b8864211b88ed7521e9af514590639344af38910Timo Sirainen NULL, 0);
c3cb859d93a77d52d6af054d358b55d45b4a5188Timo Sirainen }
b8864211b88ed7521e9af514590639344af38910Timo Sirainen
c3cb859d93a77d52d6af054d358b55d45b4a5188Timo Sirainen /* remove skipped data from hdr_buf */
c3cb859d93a77d52d6af054d358b55d45b4a5188Timo Sirainen buffer_copy(mstream->hdr_buf, 0,
c3cb859d93a77d52d6af054d358b55d45b4a5188Timo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.pos -= mstream->istream.skip;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.skip = 0;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
3403e054eacf125e757bf6c66abf0ea9f086a4b6Timo Sirainen if (mstream->header_read) {
3403e054eacf125e757bf6c66abf0ea9f086a4b6Timo Sirainen highwater_offset = mstream->istream.istream.v_offset +
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen (mstream->istream.pos - mstream->istream.skip);
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen if (highwater_offset >= mstream->header_size.virtual_size) {
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen /* we want to return mixed headers and body */
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen size_t body_highwater_size = highwater_offset -
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen mstream->header_size.virtual_size;
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen return read_mixed(mstream, body_highwater_size);
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen }
930d6db2ee2bbafd3c7cdaa39855ddccb999522fTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen &hdr)) > 0) {
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->cur_line++;
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen if (hdr->eoh) {
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen matched = TRUE;
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen if (!mstream->header_parsed &&
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->callback != NULL) {
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->callback(hdr, &matched,
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->context);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen }
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!matched)
01e29d9d23a1844b4582592a473a3b3eac56b36bTimo Sirainen continue;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->crlf)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(mstream->hdr_buf, "\r\n", 2);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen else
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen continue;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen matched = mstream->headers_count == 0 ? FALSE :
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen bsearch(hdr->name, mstream->headers,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->headers_count,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen sizeof(*mstream->headers),
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen bsearch_strcasecmp) != NULL;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->callback == NULL) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* nothing gets excluded */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen } else if (mstream->cur_line > mstream->parsed_lines) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* first time in this line */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen bool orig_matched = matched;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->parsed_lines = mstream->cur_line;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->callback(hdr, &matched, mstream->context);
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen if (matched != orig_matched) {
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen i_array_init(&mstream->match_change_lines, 8);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen array_append(&mstream->match_change_lines,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen &mstream->cur_line, 1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen } else {
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen /* second time in this line. was it excluded by the
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen callback the first time? */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (match_line_changed(mstream))
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen matched = !matched;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen if (matched == mstream->exclude) {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen /* ignore */
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen } else {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!hdr->continued) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(mstream->hdr_buf,
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen hdr->name, hdr->name_len);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(mstream->hdr_buf,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hdr->middle, hdr->middle_len);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(mstream->hdr_buf,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hdr->value, hdr->value_len);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!hdr->no_newline) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->crlf) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append(mstream->hdr_buf,
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen "\r\n", 2);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen } else
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen if (mstream->skip_count >= mstream->hdr_buf->used) {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen /* we need more */
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen mstream->skip_count -= mstream->hdr_buf->used;
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen } else {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen if (mstream->skip_count > 0) {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen mstream->istream.skip =
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen mstream->skip_count;
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen mstream->skip_count = 0;
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen break;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* don't copy eof here because we're only returning headers here.
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen the body will be returned in separate read() call. */
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.pos = pos;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (hdr_ret == 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (hdr == NULL) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* finished */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->hdr_ctx = NULL;
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!mstream->header_parsed && mstream->callback != NULL)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->callback(NULL, &matched, mstream->context);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_parsed = TRUE;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen mstream->header_read = TRUE;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_size.physical_size =
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.parent->v_offset;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_size.virtual_size =
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.istream.v_offset + pos;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ret == 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* we're at the end of headers. */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_assert(hdr == NULL);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_assert(mstream->istream.istream.v_offset +
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.pos ==
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_size.virtual_size);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return read_header(mstream);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct header_filter_istream *mstream =
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (struct header_filter_istream *)stream;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ssize_t ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen size_t pos;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!mstream->header_read ||
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.v_offset < mstream->header_size.virtual_size) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ret = read_header(mstream);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ret != -2 || stream->pos != stream->skip)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return ret;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->hide_body) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.eof = TRUE;
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen return -1;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_seek(stream->parent, mstream->istream.parent_start_offset +
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.v_offset -
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_size.virtual_size +
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_size.physical_size);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen stream->pos -= stream->skip;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->skip = 0;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (pos <= stream->pos) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return -2;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.eof = stream->parent->eof;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen } else {
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen ret = 0;
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen }
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (ret == 0 ? 0 : -1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->pos = pos;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return ret;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void parse_header(struct header_filter_istream *mstream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen size_t pos;
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen while (!mstream->header_read) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (i_stream_header_filter_read(&mstream->istream) == -1)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen break;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (void)i_stream_get_data(&mstream->istream.istream, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_skip(&mstream->istream.istream, pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void i_stream_header_filter_seek(struct istream_private *stream,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct header_filter_istream *mstream =
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen (struct header_filter_istream *)stream;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen parse_header(mstream);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.v_offset = v_offset;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->skip = stream->pos = 0;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->buffer = NULL;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (mstream->hdr_ctx != NULL) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->hdr_ctx = NULL;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (v_offset < mstream->header_size.virtual_size) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* seek into headers. we'll have to re-parse them, use
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen skip_count to set the wanted position */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset);
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen mstream->skip_count = v_offset;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->cur_line = 0;
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen mstream->header_read = FALSE;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen } else {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* body */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen v_offset += mstream->header_size.physical_size -
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->header_size.virtual_size;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_seek(stream->parent,
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen stream->parent_start_offset + v_offset);
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void ATTR_NORETURN
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Siraineni_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED)
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen{
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_panic("istream-header-filter sync() not implemented");
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic const struct stat *
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Siraineni_stream_header_filter_stat(struct istream_private *stream, bool exact)
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen{
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen struct header_filter_istream *mstream =
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen (struct header_filter_istream *)stream;
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen const struct stat *st;
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen st = i_stream_stat(stream->parent, exact);
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen if (st == NULL || st->st_size == -1 || !exact)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return st;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen parse_header(mstream);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->statbuf = *st;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->statbuf.st_size -=
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (off_t)mstream->header_size.physical_size -
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen (off_t)mstream->header_size.virtual_size;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen return &stream->statbuf;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen#undef i_stream_create_header_filter
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstruct istream *
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Siraineni_stream_create_header_filter(struct istream *input,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen enum header_filter_flags flags,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const char *const *headers,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int headers_count,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen header_filter_callback *callback, void *context)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen struct header_filter_istream *mstream;
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen unsigned int i;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream = i_new(struct header_filter_istream, 1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->pool = pool_alloconly_create(MEMPOOL_GROWING
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen "header filter stream", 4096);
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen mstream->headers = headers_count == 0 ? NULL :
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen p_new(mstream->pool, const char *, headers_count);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen for (i = 0; i < headers_count; i++)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->headers[i] = p_strdup(mstream->pool, headers[i]);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->headers_count = headers_count;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->hdr_buf = buffer_create_dynamic(mstream->pool, 1024);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->callback = callback;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->context = context;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->crlf = (flags & HEADER_FILTER_NO_CR) == 0;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen mstream->hide_body = (flags & HEADER_FILTER_HIDE_BODY) != 0;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.iostream.set_max_buffer_size =
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_header_filter_set_max_buffer_size;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.read = i_stream_header_filter_read;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.seek = i_stream_header_filter_seek;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen mstream->istream.sync = i_stream_header_filter_sync;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen mstream->istream.stat = i_stream_header_filter_stat;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen mstream->istream.istream.blocking = input->blocking;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen mstream->istream.istream.seekable = input->seekable;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_ref(input);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return i_stream_create(&mstream->istream, input, -1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen