dovecot-2.2: lib-mail: Added istream-attachment-[connector|extra...
dovecot at dovecot.org
dovecot at dovecot.org
Fri Jun 29 08:01:25 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/ffab35ef2e5b
changeset: 14698:ffab35ef2e5b
user: Timo Sirainen <tss at iki.fi>
date: Fri Jun 29 08:00:19 2012 +0300
description:
lib-mail: Added istream-attachment-[connector|extractor].
istream-attachment-extractor can be used to parse messages and extract
attachment MIME parts from them to wanted output streams. The attachments
are base64-decoded if they can be later re-encoded to original input without
any changes.
istream-attachment-connector does the reverse by taking the base istream and
attachment istreams and merging them together to create the original
istream.
diffstat:
src/lib-mail/Makefile.am | 20 +-
src/lib-mail/istream-attachment-connector.c | 123 ++++
src/lib-mail/istream-attachment-connector.h | 26 +
src/lib-mail/istream-attachment-extractor.c | 689 ++++++++++++++++++++++++++++
src/lib-mail/istream-attachment-extractor.h | 59 ++
src/lib-mail/test-istream-attachment.c | 293 +++++++++++
6 files changed, 1208 insertions(+), 2 deletions(-)
diffs (truncated from 1262 to 300 lines):
diff -r 69334bf138cf -r ffab35ef2e5b src/lib-mail/Makefile.am
--- a/src/lib-mail/Makefile.am Fri Jun 29 07:56:02 2012 +0300
+++ b/src/lib-mail/Makefile.am Fri Jun 29 08:00:19 2012 +0300
@@ -6,6 +6,8 @@
-I$(top_srcdir)/src/lib-charset
libmail_la_SOURCES = \
+ istream-attachment-connector.c \
+ istream-attachment-extractor.c \
istream-binary-converter.c \
istream-dot.c \
istream-header-filter.c \
@@ -29,6 +31,8 @@
rfc822-parser.c
headers = \
+ istream-attachment-connector.h \
+ istream-attachment-extractor.h \
istream-binary-converter.h \
istream-dot.h \
istream-header-filter.h \
@@ -57,6 +61,7 @@
test_programs = \
test-istream-dot \
+ test-istream-attachment \
test-istream-binary-converter \
test-istream-header-filter \
test-mbox-from \
@@ -81,9 +86,20 @@
test_istream_dot_LDADD = istream-dot.lo $(test_libs)
test_istream_dot_DEPENDENCIES = istream-dot.lo $(test_libs)
+message_parser_objects = \
+ message-parser.lo \
+ message-header-parser.lo \
+ message-size.lo \
+ rfc822-parser.lo \
+ rfc2231-parser.lo
+
test_istream_binary_converter_SOURCES = test-istream-binary-converter.c
-test_istream_binary_converter_LDADD = istream-binary-converter.lo message-parser.lo message-header-parser.lo message-size.lo rfc822-parser.lo rfc2231-parser.lo $(test_libs)
-test_istream_binary_converter_DEPENDENCIES = istream-binary-converter.lo message-parser.lo message-header-parser.lo message-size.lo rfc822-parser.lo rfc2231-parser.lo $(test_libs)
+test_istream_binary_converter_LDADD = istream-binary-converter.lo $(message_parser_objects) $(test_libs)
+test_istream_binary_converter_DEPENDENCIES = istream-binary-converter.lo $(message_parser_objects) $(test_libs)
+
+test_istream_attachment_SOURCES = test-istream-attachment.c
+test_istream_attachment_LDADD = istream-attachment-extractor.lo istream-attachment-connector.lo $(message_parser_objects) $(test_libs)
+test_istream_attachment_DEPENDENCIES = istream-attachment-extractor.lo istream-attachment-connector.lo $(message_parser_objects) $(test_libs)
test_istream_header_filter_SOURCES = test-istream-header-filter.c
test_istream_header_filter_LDADD = istream-header-filter.lo message-header-parser.lo $(test_libs)
diff -r 69334bf138cf -r ffab35ef2e5b src/lib-mail/istream-attachment-connector.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-mail/istream-attachment-connector.c Fri Jun 29 08:00:19 2012 +0300
@@ -0,0 +1,123 @@
+/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "istream.h"
+#include "istream-concat.h"
+#include "istream-sized.h"
+#include "istream-base64-encoder.h"
+#include "istream-attachment-connector.h"
+
+struct istream_attachment_connector {
+ pool_t pool;
+ struct istream *base_input;
+ uoff_t msg_size;
+
+ uoff_t encoded_offset;
+ ARRAY_DEFINE(streams, struct istream *);
+};
+
+struct istream_attachment_connector *
+istream_attachment_connector_begin(struct istream *base_input, uoff_t msg_size)
+{
+ struct istream_attachment_connector *conn;
+ pool_t pool;
+
+ pool = pool_alloconly_create("istream-attachment-connector", 1024);
+ conn = p_new(pool, struct istream_attachment_connector, 1);
+ conn->pool = pool;
+ conn->base_input = base_input;
+ conn->msg_size = msg_size;
+ p_array_init(&conn->streams, pool, 8);
+ i_stream_ref(conn->base_input);
+ return conn;
+}
+
+int istream_attachment_connector_add(struct istream_attachment_connector *conn,
+ struct istream *decoded_input,
+ uoff_t start_offset, uoff_t encoded_size,
+ unsigned int base64_blocks_per_line,
+ bool base64_have_crlf,
+ const char **error_r)
+{
+ struct istream *input, *input2;
+ uoff_t base_prefix_size;
+
+ if (start_offset < conn->encoded_offset) {
+ *error_r = t_strdup_printf(
+ "Attachment %s points before the previous attachment "
+ "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
+ i_stream_get_name(decoded_input),
+ start_offset, conn->encoded_offset);
+ return -1;
+ }
+ base_prefix_size = start_offset - conn->encoded_offset;
+ if (start_offset + encoded_size > conn->msg_size) {
+ *error_r = t_strdup_printf(
+ "Attachment %s points outside message "
+ "(%"PRIuUOFF_T" + %"PRIuUOFF_T" > %"PRIuUOFF_T")",
+ i_stream_get_name(decoded_input),
+ start_offset, encoded_size,
+ conn->msg_size);
+ return -1;
+ }
+
+ if (base_prefix_size > 0) {
+ /* add a part of the base message before the attachment */
+ input = i_stream_create_limit(conn->base_input,
+ base_prefix_size);
+ array_append(&conn->streams, &input, 1);
+ i_stream_skip(conn->base_input, base_prefix_size);
+ conn->encoded_offset += base_prefix_size;
+ }
+ conn->encoded_offset += encoded_size;
+
+ if (base64_blocks_per_line == 0) {
+ input = decoded_input;
+ i_stream_ref(input);
+ } else {
+ input = i_stream_create_base64_encoder(decoded_input,
+ base64_blocks_per_line*4,
+ base64_have_crlf);
+ }
+ input2 = i_stream_create_sized(input, encoded_size);
+ array_append(&conn->streams, &input2, 1);
+ i_stream_unref(&input);
+ return 0;
+}
+
+struct istream *
+istream_attachment_connector_finish(struct istream_attachment_connector **_conn)
+{
+ struct istream_attachment_connector *conn = *_conn;
+ struct istream **inputs, *input;
+ uoff_t trailer_size;
+
+ *_conn = NULL;
+
+ if (conn->base_input->v_offset != conn->msg_size) {
+ i_assert(conn->base_input->v_offset < conn->msg_size);
+
+ trailer_size = conn->msg_size - conn->encoded_offset;
+ input = i_stream_create_limit(conn->base_input, trailer_size);
+ array_append(&conn->streams, &input, 1);
+ }
+ array_append_zero(&conn->streams);
+
+ inputs = array_idx_modifiable(&conn->streams, 0);
+ input = i_stream_create_concat(inputs);
+
+ i_stream_unref(&conn->base_input);
+ pool_unref(&conn->pool);
+ return input;
+}
+
+void istream_attachment_connector_abort(struct istream_attachment_connector **_conn)
+{
+ struct istream_attachment_connector *conn = *_conn;
+
+ *_conn = NULL;
+
+ i_stream_unref(&conn->base_input);
+ pool_unref(&conn->pool);
+}
diff -r 69334bf138cf -r ffab35ef2e5b src/lib-mail/istream-attachment-connector.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-mail/istream-attachment-connector.h Fri Jun 29 08:00:19 2012 +0300
@@ -0,0 +1,26 @@
+#ifndef ISTREAM_ATTACHMENT_CONNECTOR_H
+#define ISTREAM_ATTACHMENT_CONNECTOR_H
+
+/* Start building a message stream. The base_input contains the message
+ without attachments. The final stream must be exactly msg_size bytes. */
+struct istream_attachment_connector *
+istream_attachment_connector_begin(struct istream *base_input, uoff_t msg_size);
+
+/* Add the given input stream as attachment. The attachment starts at the given
+ start_offset in the (original) message. If base64_blocks_per_line is
+ non-zero, the input is base64-encoded with the given settings. The
+ (resulting base64-encoded) input must have exactly encoded_size bytes.
+
+ Returns 0 if the input was ok, -1 if we've already reached msg_size */
+int istream_attachment_connector_add(struct istream_attachment_connector *conn,
+ struct istream *decoded_input,
+ uoff_t start_offset, uoff_t encoded_size,
+ unsigned int base64_blocks_per_line,
+ bool base64_have_crlf,
+ const char **error_r);
+
+struct istream *
+istream_attachment_connector_finish(struct istream_attachment_connector **conn);
+void istream_attachment_connector_abort(struct istream_attachment_connector **conn);
+
+#endif
diff -r 69334bf138cf -r ffab35ef2e5b src/lib-mail/istream-attachment-extractor.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-mail/istream-attachment-extractor.c Fri Jun 29 08:00:19 2012 +0300
@@ -0,0 +1,689 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream-private.h"
+#include "ostream.h"
+#include "base64.h"
+#include "buffer.h"
+#include "str.h"
+#include "hash-format.h"
+#include "rfc822-parser.h"
+#include "message-parser.h"
+#include "istream-attachment-extractor.h"
+
+#define BASE64_ATTACHMENT_MAX_EXTRA_BYTES 1024
+
+enum mail_attachment_state {
+ MAIL_ATTACHMENT_STATE_NO,
+ MAIL_ATTACHMENT_STATE_MAYBE,
+ MAIL_ATTACHMENT_STATE_YES
+};
+
+enum base64_state {
+ BASE64_STATE_0 = 0,
+ BASE64_STATE_1,
+ BASE64_STATE_2,
+ BASE64_STATE_3,
+ BASE64_STATE_CR,
+ BASE64_STATE_EOB,
+ BASE64_STATE_EOM
+};
+
+struct attachment_istream_part {
+ char *content_type, *content_disposition;
+ enum mail_attachment_state state;
+ /* start offset of the message part in the original input stream */
+ uoff_t start_offset;
+
+ /* for saving attachments base64-decoded: */
+ enum base64_state base64_state;
+ unsigned int base64_line_blocks, cur_base64_blocks;
+ uoff_t base64_bytes;
+ bool base64_have_crlf; /* CRLF linefeeds */
+ bool base64_failed;
+
+ int temp_fd;
+ struct ostream *temp_output;
+ buffer_t *part_buf;
+};
+
+struct attachment_istream {
+ struct istream_private istream;
+ pool_t pool;
+
+ struct istream_attachment_settings set;
+ void *context;
+
+ struct message_parser_ctx *parser;
+ struct message_part *cur_part;
+ struct attachment_istream_part part;
+
+ bool retry_read;
+};
+
+static void stream_add_data(struct attachment_istream *astream,
+ const void *data, size_t size)
+{
+ if (size > 0) {
+ memcpy(i_stream_alloc(&astream->istream, size), data, size);
+ astream->istream.pos += size;
+ }
+}
+
+static void parse_content_type(struct attachment_istream *astream,
+ const struct message_header_line *hdr)
+{
+ struct rfc822_parser_context parser;
+ string_t *content_type;
+
+ rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
+ rfc822_skip_lwsp(&parser);
+
+ T_BEGIN {
+ content_type = t_str_new(64);
+ if (rfc822_parse_content_type(&parser, content_type) >= 0) {
+ i_free(astream->part.content_type);
+ astream->part.content_type =
+ i_strdup(str_c(content_type));
More information about the dovecot-cvs
mailing list