From: Timo Sirainen Date: Sun, 20 Jun 2004 06:20:32 +0000 (+0300) Subject: Added istream-header-filter, which allows filtering specified headers from X-Git-Tag: 1.1.alpha1~3910 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b82e145e384466f60dda7e349505e1092938345f;p=thirdparty%2Fdovecot%2Fcore.git Added istream-header-filter, which allows filtering specified headers from input stream. --HG-- branch : HEAD --- diff --git a/src/lib-mail/Makefile.am b/src/lib-mail/Makefile.am index 453952c278..80c1982c1a 100644 --- a/src/lib-mail/Makefile.am +++ b/src/lib-mail/Makefile.am @@ -5,6 +5,7 @@ INCLUDES = \ -I$(top_srcdir)/src/lib-charset libmail_a_SOURCES = \ + istream-header-filter.c \ message-address.c \ message-body-search.c \ message-content-parser.c \ @@ -19,6 +20,7 @@ libmail_a_SOURCES = \ quoted-printable.c noinst_HEADERS = \ + istream-header-filter.h \ mail-types.h \ message-address.h \ message-body-search.h \ diff --git a/src/lib-mail/istream-header-filter.c b/src/lib-mail/istream-header-filter.c new file mode 100644 index 0000000000..623ac7a50c --- /dev/null +++ b/src/lib-mail/istream-header-filter.c @@ -0,0 +1,183 @@ +/* Copyright (C) 2003-2004 Timo Sirainen */ + +/* FIXME: the header wouldn't necessarily have to be read in memory. we could + just parse it forward in _read(). */ + +#include "lib.h" +#include "buffer.h" +#include "message-parser.h" +#include "istream-internal.h" +#include "istream-header-filter.h" + +#include + +struct header_filter_istream { + struct _istream istream; + + struct istream *input; + + buffer_t *headers; + struct message_size header_size; +}; + +static void _close(struct _iostream *stream __attr_unused__) +{ +} + +static void _destroy(struct _iostream *stream) +{ + struct header_filter_istream *mstream = + (struct header_filter_istream *)stream; + + i_stream_unref(mstream->input); + buffer_free(mstream->headers); +} + +static void _set_max_buffer_size(struct _iostream *stream, size_t max_size) +{ + struct header_filter_istream *mstream = + (struct header_filter_istream *)stream; + + i_stream_set_max_buffer_size(mstream->input, max_size); +} + +static void _set_blocking(struct _iostream *stream, int timeout_msecs, + void (*timeout_cb)(void *), void *context) +{ + struct header_filter_istream *mstream = + (struct header_filter_istream *)stream; + + i_stream_set_blocking(mstream->input, timeout_msecs, + timeout_cb, context); +} + +static ssize_t _read(struct _istream *stream) +{ + struct header_filter_istream *mstream = + (struct header_filter_istream *)stream; + ssize_t ret; + size_t pos; + + if (stream->istream.v_offset < mstream->header_size.virtual_size) { + /* we don't support mixing headers and body. + it shouldn't be needed. */ + return -2; + } + + if (mstream->input->v_offset - mstream->header_size.physical_size != + stream->istream.v_offset - mstream->header_size.virtual_size) { + i_stream_seek(mstream->input, stream->istream.v_offset - + mstream->header_size.virtual_size + + mstream->header_size.physical_size); + } + + ret = i_stream_read(mstream->input); + + mstream->istream.pos -= mstream->istream.skip; + mstream->istream.skip = 0; + + mstream->istream.buffer = i_stream_get_data(mstream->input, &pos); + if (pos <= mstream->istream.pos) { + i_assert(ret <= 0); + } else { + ret = pos - mstream->istream.pos; + mstream->istream.pos = pos; + } + + return ret; +} + +static void _seek(struct _istream *stream, uoff_t v_offset) +{ + struct header_filter_istream *mstream = + (struct header_filter_istream *)stream; + + stream->istream.v_offset = v_offset; + if (v_offset < mstream->header_size.virtual_size) { + /* still in headers */ + stream->skip = v_offset; + stream->pos = mstream->header_size.virtual_size; + stream->buffer = buffer_get_data(mstream->headers, NULL); + } else { + /* body - use our real input stream */ + stream->skip = stream->pos = 0; + stream->buffer = NULL; + + v_offset += mstream->header_size.physical_size - + mstream->header_size.virtual_size; + i_stream_seek(mstream->input, v_offset); + } +} + +static void read_and_hide_headers(struct istream *input, + const char *const *headers, + size_t headers_count, buffer_t *dest, + struct message_size *hdr_size) +{ + struct message_header_parser_ctx *hdr_ctx; + struct message_header_line *hdr; + uoff_t virtual_size = 0; + + hdr_ctx = message_parse_header_init(input, hdr_size, FALSE); + while ((hdr = message_parse_header_next(hdr_ctx)) != NULL) { + if (hdr->eoh) { + if (dest != NULL) + buffer_append(dest, "\r\n", 2); + else + virtual_size += 2; + break; + } + + if (bsearch(hdr->name, headers, headers_count, + sizeof(*headers), bsearch_strcasecmp) != NULL) { + /* ignore */ + } else if (dest != NULL) { + if (!hdr->continued) { + buffer_append(dest, hdr->name, hdr->name_len); + buffer_append(dest, ": ", 2); + } + buffer_append(dest, hdr->value, hdr->value_len); + buffer_append(dest, "\r\n", 2); + } else { + if (!hdr->continued) + virtual_size += hdr->name_len + 2; + virtual_size += hdr->value_len + 2; + } + } + message_parse_header_deinit(hdr_ctx); + + if (dest != NULL) + virtual_size = buffer_get_used_size(dest); + + hdr_size->virtual_size = virtual_size; + hdr_size->lines = 0; +} + +struct istream * +i_stream_create_header_filter(pool_t pool, struct istream *input, + const char *const *headers, size_t headers_count) +{ + struct header_filter_istream *mstream; + + mstream = p_new(pool, struct header_filter_istream, 1); + mstream->input = input; + i_stream_ref(mstream->input); + + mstream->headers = buffer_create_dynamic(default_pool, + 8192, (size_t)-1); + read_and_hide_headers(input, headers, headers_count, mstream->headers, + &mstream->header_size); + + mstream->istream.buffer = buffer_get_data(mstream->headers, NULL); + mstream->istream.pos = mstream->header_size.virtual_size; + + mstream->istream.iostream.close = _close; + mstream->istream.iostream.destroy = _destroy; + mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size; + mstream->istream.iostream.set_blocking = _set_blocking; + + mstream->istream.read = _read; + mstream->istream.seek = _seek; + + return _i_stream_create(&mstream->istream, pool, -1, 0); +} diff --git a/src/lib-mail/istream-header-filter.h b/src/lib-mail/istream-header-filter.h new file mode 100644 index 0000000000..a36b27da8a --- /dev/null +++ b/src/lib-mail/istream-header-filter.h @@ -0,0 +1,9 @@ +#ifndef __ISTREAM_HEADER_FILTER_H +#define __ISTREAM_HEADER_FILTER_H + +/* NOTE: NULL-terminated headers list must be sorted. */ +struct istream * +i_stream_create_header_filter(pool_t pool, struct istream *input, + const char *const *headers, size_t headers_count); + +#endif