1
/* Copyright (c) 2003-2013 Dovecot authors, see the included COPYING file */
6
#include "istream-concat.h"
7
#include "istream-sized.h"
8
#include "istream-base64.h"
9
#include "istream-attachment-connector.h"
11
struct istream_attachment_connector {
13
struct istream *base_input;
14
uoff_t base_input_offset, msg_size;
16
uoff_t encoded_offset;
17
ARRAY(struct istream *) streams;
20
struct istream_attachment_connector *
21
istream_attachment_connector_begin(struct istream *base_input, uoff_t msg_size)
23
struct istream_attachment_connector *conn;
26
pool = pool_alloconly_create("istream-attachment-connector", 1024);
27
conn = p_new(pool, struct istream_attachment_connector, 1);
29
conn->base_input = base_input;
30
conn->base_input_offset = base_input->v_offset;
31
conn->msg_size = msg_size;
32
p_array_init(&conn->streams, pool, 8);
33
i_stream_ref(conn->base_input);
37
int istream_attachment_connector_add(struct istream_attachment_connector *conn,
38
struct istream *decoded_input,
39
uoff_t start_offset, uoff_t encoded_size,
40
unsigned int base64_blocks_per_line,
41
bool base64_have_crlf,
44
struct istream *input, *input2;
45
uoff_t base_prefix_size;
47
if (start_offset < conn->encoded_offset) {
48
*error_r = t_strdup_printf(
49
"Attachment %s points before the previous attachment "
50
"(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
51
i_stream_get_name(decoded_input),
52
start_offset, conn->encoded_offset);
55
base_prefix_size = start_offset - conn->encoded_offset;
56
if (start_offset + encoded_size > conn->msg_size) {
57
*error_r = t_strdup_printf(
58
"Attachment %s points outside message "
59
"(%"PRIuUOFF_T" + %"PRIuUOFF_T" > %"PRIuUOFF_T")",
60
i_stream_get_name(decoded_input),
61
start_offset, encoded_size,
66
if (base_prefix_size > 0) {
67
/* add a part of the base message before the attachment */
68
input = i_stream_create_range(conn->base_input,
69
conn->base_input_offset,
71
array_append(&conn->streams, &input, 1);
72
conn->base_input_offset += base_prefix_size;
73
conn->encoded_offset += base_prefix_size;
75
conn->encoded_offset += encoded_size;
77
if (base64_blocks_per_line == 0) {
78
input = decoded_input;
81
input = i_stream_create_base64_encoder(decoded_input,
82
base64_blocks_per_line*4,
84
i_stream_set_name(input, t_strdup_printf("%s[base64:%u b/l%s]",
85
i_stream_get_name(decoded_input),
86
base64_blocks_per_line,
87
base64_have_crlf ? ",crlf" : ""));
89
input2 = i_stream_create_sized(input, encoded_size);
90
array_append(&conn->streams, &input2, 1);
91
i_stream_unref(&input);
96
istream_attachment_connector_free(struct istream_attachment_connector *conn)
98
struct istream *const *streamp, *stream;
100
array_foreach(&conn->streams, streamp) {
103
i_stream_unref(&stream);
105
i_stream_unref(&conn->base_input);
106
pool_unref(&conn->pool);
110
istream_attachment_connector_finish(struct istream_attachment_connector **_conn)
112
struct istream_attachment_connector *conn = *_conn;
113
struct istream **inputs, *input;
118
if (conn->base_input_offset != conn->msg_size) {
119
i_assert(conn->base_input_offset < conn->msg_size);
121
trailer_size = conn->msg_size - conn->encoded_offset;
122
input = i_stream_create_range(conn->base_input,
123
conn->base_input_offset,
125
array_append(&conn->streams, &input, 1);
127
array_append_zero(&conn->streams);
129
inputs = array_idx_modifiable(&conn->streams, 0);
130
input = i_stream_create_concat(inputs);
132
istream_attachment_connector_free(conn);
136
void istream_attachment_connector_abort(struct istream_attachment_connector **_conn)
138
struct istream_attachment_connector *conn = *_conn;
142
istream_attachment_connector_free(conn);