bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen#include "lib.h"
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen#include "array.h"
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen#include "istream.h"
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen#include "istream-concat.h"
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen#include "istream-sized.h"
12467c3e1d2c077862ad7545677182f695d17919Timo Sirainen#include "istream-base64.h"
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen#include "istream-attachment-connector.h"
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstruct istream_attachment_connector {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen pool_t pool;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream *base_input;
f5f8bd05b524864d0ae678cd7d08e60b0e277feeTimo Sirainen uoff_t base_input_offset, msg_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen uoff_t encoded_offset;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct istream *) streams;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen};
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstruct istream_attachment_connector *
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenistream_attachment_connector_begin(struct istream *base_input, uoff_t msg_size)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen{
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream_attachment_connector *conn;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen pool_t pool;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen pool = pool_alloconly_create("istream-attachment-connector", 1024);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn = p_new(pool, struct istream_attachment_connector, 1);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn->pool = pool;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn->base_input = base_input;
f5f8bd05b524864d0ae678cd7d08e60b0e277feeTimo Sirainen conn->base_input_offset = base_input->v_offset;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn->msg_size = msg_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen p_array_init(&conn->streams, pool, 8);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_stream_ref(conn->base_input);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen return conn;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen}
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenint istream_attachment_connector_add(struct istream_attachment_connector *conn,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream *decoded_input,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen uoff_t start_offset, uoff_t encoded_size,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen unsigned int base64_blocks_per_line,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen bool base64_have_crlf,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen const char **error_r)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen{
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream *input, *input2;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen uoff_t base_prefix_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (start_offset < conn->encoded_offset) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = t_strdup_printf(
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen "Attachment %s points before the previous attachment "
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_stream_get_name(decoded_input),
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen start_offset, conn->encoded_offset);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen return -1;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen }
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen base_prefix_size = start_offset - conn->encoded_offset;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (start_offset + encoded_size > conn->msg_size) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = t_strdup_printf(
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen "Attachment %s points outside message "
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen "(%"PRIuUOFF_T" + %"PRIuUOFF_T" > %"PRIuUOFF_T")",
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_stream_get_name(decoded_input),
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen start_offset, encoded_size,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn->msg_size);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen return -1;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen }
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (base_prefix_size > 0) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* add a part of the base message before the attachment */
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen input = i_stream_create_min_sized_range(conn->base_input,
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen conn->base_input_offset, base_prefix_size);
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen i_stream_set_name(input, t_strdup_printf("%s middle",
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen i_stream_get_name(conn->base_input)));
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen array_append(&conn->streams, &input, 1);
f5f8bd05b524864d0ae678cd7d08e60b0e277feeTimo Sirainen conn->base_input_offset += base_prefix_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn->encoded_offset += base_prefix_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen }
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen conn->encoded_offset += encoded_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (base64_blocks_per_line == 0) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen input = decoded_input;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_stream_ref(input);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen } else {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen input = i_stream_create_base64_encoder(decoded_input,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen base64_blocks_per_line*4,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen base64_have_crlf);
08997487a0de72a0e77ff73d54e0ae228f1d5908Timo Sirainen i_stream_set_name(input, t_strdup_printf("%s[base64:%u b/l%s]",
08997487a0de72a0e77ff73d54e0ae228f1d5908Timo Sirainen i_stream_get_name(decoded_input),
08997487a0de72a0e77ff73d54e0ae228f1d5908Timo Sirainen base64_blocks_per_line,
08997487a0de72a0e77ff73d54e0ae228f1d5908Timo Sirainen base64_have_crlf ? ",crlf" : ""));
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen }
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen input2 = i_stream_create_sized(input, encoded_size);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen array_append(&conn->streams, &input2, 1);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_stream_unref(&input);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen return 0;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen}
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainenstatic void
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainenistream_attachment_connector_free(struct istream_attachment_connector *conn)
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen{
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen struct istream *const *streamp, *stream;
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen array_foreach(&conn->streams, streamp) {
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen stream = *streamp;
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&stream);
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen }
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen i_stream_unref(&conn->base_input);
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen pool_unref(&conn->pool);
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen}
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstruct istream *
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenistream_attachment_connector_finish(struct istream_attachment_connector **_conn)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen{
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream_attachment_connector *conn = *_conn;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream **inputs, *input;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen uoff_t trailer_size;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *_conn = NULL;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
f5f8bd05b524864d0ae678cd7d08e60b0e277feeTimo Sirainen if (conn->base_input_offset != conn->msg_size) {
f5f8bd05b524864d0ae678cd7d08e60b0e277feeTimo Sirainen i_assert(conn->base_input_offset < conn->msg_size);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen if (conn->msg_size != (uoff_t)-1) {
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen trailer_size = conn->msg_size - conn->encoded_offset;
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen input = i_stream_create_sized_range(conn->base_input,
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen conn->base_input_offset,
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen trailer_size);
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen i_stream_set_name(input, t_strdup_printf(
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen "%s trailer", i_stream_get_name(conn->base_input)));
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen } else {
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen input = i_stream_create_range(conn->base_input,
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen conn->base_input_offset,
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen (uoff_t)-1);
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen }
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen array_append(&conn->streams, &input, 1);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen }
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen array_append_zero(&conn->streams);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen inputs = array_idx_modifiable(&conn->streams, 0);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen input = i_stream_create_concat(inputs);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen istream_attachment_connector_free(conn);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen return input;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen}
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenvoid istream_attachment_connector_abort(struct istream_attachment_connector **_conn)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen{
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct istream_attachment_connector *conn = *_conn;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *_conn = NULL;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen
96b8965a967dcaef1316f4f32d5cd956d844201bTimo Sirainen istream_attachment_connector_free(conn);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen}