]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added istream-header-filter, which allows filtering specified headers from
authorTimo Sirainen <tss@iki.fi>
Sun, 20 Jun 2004 06:20:32 +0000 (09:20 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 20 Jun 2004 06:20:32 +0000 (09:20 +0300)
input stream.

--HG--
branch : HEAD

src/lib-mail/Makefile.am
src/lib-mail/istream-header-filter.c [new file with mode: 0644]
src/lib-mail/istream-header-filter.h [new file with mode: 0644]

index 453952c2783c3713ff7a27fed923dcc9065055ea..80c1982c1a51d218836b721307d03ca759f3e9df 100644 (file)
@@ -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 (file)
index 0000000..623ac7a
--- /dev/null
@@ -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 <stdlib.h>
+
+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 (file)
index 0000000..a36b27d
--- /dev/null
@@ -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