istream-header-filter.c revision 221351ed85c839e0b03d82c47654c3d17202e3db
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen const char **headers;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen ARRAY_DEFINE(match_change_lines, unsigned int);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic void i_stream_header_filter_destroy(struct iostream_private *stream)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (array_is_created(&mstream->match_change_lines))
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Siraineni_stream_header_filter_set_max_buffer_size(struct iostream_private *stream,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_set_max_buffer_size(mstream->istream.parent, max_size);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenread_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const unsigned char *data;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.istream.eof = mstream->istream.parent->eof;
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen data = i_stream_get_data(mstream->istream.parent, &pos);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen buffer_append(mstream->hdr_buf, data + body_highwater_size,
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainenstatic int cmp_uint(const void *p1, const void *p2)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic bool match_line_changed(struct header_filter_istream *mstream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const unsigned int *lines;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int count;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!array_is_created(&mstream->match_change_lines))
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen lines = array_get(&mstream->match_change_lines, &count);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen return bsearch(&mstream->cur_line, lines, count, sizeof(*lines),
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
b8864211b88ed7521e9af514590639344af38910Timo Sirainen message_parse_header_init(mstream->istream.parent,
c3cb859d93a77d52d6af054d358b55d45b4a5188Timo Sirainen /* remove skipped data from hdr_buf */
c3cb859d93a77d52d6af054d358b55d45b4a5188Timo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.pos -= mstream->istream.skip;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
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 return read_mixed(mstream, body_highwater_size);
aa938aea66562ca3f3c5965a79b3b27ebcbe04efTimo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen matched = mstream->headers_count == 0 ? FALSE :
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* nothing gets excluded */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen } else if (mstream->cur_line > mstream->parsed_lines) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* first time in this line */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->callback(hdr, &matched, mstream->context);
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen i_array_init(&mstream->match_change_lines, 8);
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen /* second time in this line. was it excluded by the
3b8a19184c37851d9794178dd7a612ed8ed1c4f8Timo Sirainen callback the first time? */
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen if (mstream->skip_count >= mstream->hdr_buf->used) {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen /* we need more */
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen mstream->skip_count -= mstream->hdr_buf->used;
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 /* finished */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (!mstream->header_parsed && mstream->callback != NULL)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->callback(NULL, &matched, mstream->context);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* we're at the end of headers. */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic ssize_t i_stream_header_filter_read(struct istream_private *stream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.v_offset < mstream->header_size.virtual_size) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_seek(stream->parent, mstream->istream.parent_start_offset +
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void parse_header(struct header_filter_istream *mstream)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (i_stream_header_filter_read(&mstream->istream) == -1)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (void)i_stream_get_data(&mstream->istream.istream, &pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_stream_skip(&mstream->istream.istream, pos);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void i_stream_header_filter_seek(struct istream_private *stream,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
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);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen v_offset += mstream->header_size.physical_size -
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Siraineni_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_panic("istream-header-filter sync() not implemented");
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic const struct stat *
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Siraineni_stream_header_filter_stat(struct istream_private *stream, bool exact)
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen if (st == NULL || st->st_size == -1 || !exact)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Siraineni_stream_create_header_filter(struct istream *input,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const char *const *headers,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen header_filter_callback *callback, void *context)
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen unsigned int i;
77bc2bda5b781c4ffddc8a74b175cf32e9e2c2ecTimo Sirainen i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream = i_new(struct header_filter_istream, 1);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->pool = pool_alloconly_create(MEMPOOL_GROWING
fad068d459cc7b04fedade4e0bb343be62e6d310Timo Sirainen mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
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->hdr_buf = buffer_create_dynamic(mstream->pool, 1024);
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;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen mstream->istream.iostream.set_max_buffer_size =
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 mstream->istream.istream.blocking = input->blocking;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen mstream->istream.istream.seekable = input->seekable;