bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainenstatic void i_stream_unref_try_inputs(struct try_istream *tstream)
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen for (unsigned int i = 0; i < tstream->try_input_count; i++) {
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainenstatic void i_stream_try_close(struct iostream_private *stream,
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen struct try_istream *tstream = (struct try_istream *)stream;
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen for (unsigned int i = 0; i < tstream->try_input_count; i++) {
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainenstatic bool i_stream_try_is_buffer_full(struct istream *try_input)
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen /* See if one of the parent istreams have their buffer full.
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen This is mainly intended to check with istream-tee whether its
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen parent is full. That means that the try_input has already seen
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen a full buffer of input, but it hasn't decided to return anything
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen yet. But it also hasn't failed, so we'll assume that the input is
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen correct for it and it simply needs a lot more input before it can
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen return anything (e.g. istream-bzlib). */
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen while (try_input->real_stream->parent != NULL) {
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen if (try_input->real_stream->pos == try_input->real_stream->buffer_size &&
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainenstatic int i_stream_try_detect(struct try_istream *tstream)
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen for (; tstream->try_idx < tstream->try_input_count; tstream->try_idx++) {
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen if (ret == 0 && i_stream_try_is_buffer_full(try_input))
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen i_stream_init_parent(&tstream->istream, try_input);
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen io_stream_set_error(&tstream->istream.iostream,
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen "Unexpected error while detecting stream format: %s",
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen /* All streams failed with EINVAL. */
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen io_stream_set_error(&tstream->istream.iostream,
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen "Failed to detect stream format");
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen tstream->istream.istream.stream_errno = EINVAL;
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Siraineni_stream_try_read(struct istream_private *stream)
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen struct try_istream *tstream = (struct try_istream *)stream;
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen if ((ret = i_stream_try_detect(tstream)) <= 0)
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen return i_stream_read_copy_from_parent(&stream->istream);
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainenstruct istream *istream_try_create(struct istream *const input[])
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen for (count = 0; input[count] != NULL; count++) {
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen tstream->try_input = p_memdup(default_pool, input,
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen tstream->istream.iostream.close = i_stream_try_close;
e9fe799e27b5a3b67c256766d4bafd388e560684Timo Sirainen tstream->istream.max_buffer_size = max_buffer_size;
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen return i_stream_create(&tstream->istream, NULL, -1, 0);