ostream-crlf.c revision e8eb96edcfe8cff7839f1258ab6e871e41a4785e
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2004 Timo Sirainen */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen/* The code is quite ugly because we want the send functions to return correcly
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen the number of input bytes consumed, not number of bytes actually sent. */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "lib.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "buffer.h"
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen#include "istream.h"
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include "ostream-internal.h"
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include "ostream-crlf.h"
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#define IOVBUF_COUNT 64
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstruct crlf_ostream {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct _ostream ostream;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct ostream *output;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen bool last_cr;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen};
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic const struct const_iovec cr_iov = { "\r", 1 };
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstatic void _close(struct _iostream *stream __attr_unused__)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic void _destroy(struct _iostream *stream)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen o_stream_unref(&cstream->output);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen o_stream_set_max_buffer_size(cstream->output, max_size);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic void _cork(struct _ostream *stream, bool set)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (set)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen o_stream_cork(cstream->output);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen else
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen o_stream_uncork(cstream->output);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic int _flush(struct _ostream *stream)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return o_stream_flush(cstream->output);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic void _flush_pending(struct _ostream *stream, bool set)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen o_stream_set_flush_pending(cstream->output, set);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic size_t _get_used_size(struct _ostream *stream)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return o_stream_get_buffer_used_size(cstream->output);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic int _seek(struct _ostream *stream, uoff_t offset)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen int ret;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen cstream->last_cr = FALSE;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = o_stream_seek(cstream->output, offset);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen stream->ostream.offset = cstream->output->offset;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return ret;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic ssize_t
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainensendv_crlf(struct crlf_ostream *cstream, const struct const_iovec *iov,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen size_t iov_count, const char *diff, ssize_t *total_r)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ssize_t ret;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen size_t i, pos;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen ret = o_stream_sendv(cstream->output, iov, iov_count);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen if (ret > 0) {
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen pos = (size_t)ret - 1;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen for (i = 0; i < iov_count && pos >= iov[i].iov_len; i++) {
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen *total_r += iov[i].iov_len + diff[i];
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen pos -= iov[i].iov_len;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen }
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen cstream->last_cr =
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen *((const char *)iov[i].iov_base + pos) == '\r';
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen if (pos + 1 == iov[i].iov_len)
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen *total_r += iov[i].iov_len + diff[i];
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen else
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen *total_r += pos;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen }
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen cstream->ostream.ostream.offset = cstream->output->offset;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return ret;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen}
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainenstatic ssize_t
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen_sendv_crlf(struct _ostream *stream, const struct const_iovec *iov,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen unsigned int iov_count)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen{
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen buffer_t *iov_buf, *diff_buf;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const unsigned char *data;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct const_iovec new_iov;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen unsigned int vec, i, len, start, new_iov_count = 0, new_iov_size = 0;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen ssize_t ret, total;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen bool last_cr;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen last_cr = cstream->last_cr;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen t_push();
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen iov_buf = buffer_create_dynamic(unsafe_data_stack_pool,
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen sizeof(struct const_iovec *) *
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen IOVBUF_COUNT);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen diff_buf = buffer_create_dynamic(unsafe_data_stack_pool, IOVBUF_COUNT);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen total = 0;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen for (vec = 0; vec < iov_count; vec++) {
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen data = iov[vec].iov_base;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen len = iov[vec].iov_len;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen for (i = start = 0;; i++) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (i != len) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (data[i] != '\n')
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen continue;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (i > 0) {
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (data[i-1] == '\r')
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen continue;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen } else {
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (last_cr)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen continue;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* need to insert CR */
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (i != start) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen new_iov.iov_base = data + start;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen new_iov.iov_len = i - start;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen buffer_append(iov_buf, &new_iov,
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen sizeof(new_iov));
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen buffer_append_c(diff_buf, 0);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen new_iov_count++;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen new_iov_size += new_iov.iov_len;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen start = i;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (i != len) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen buffer_append(iov_buf, &cr_iov, sizeof(cr_iov));
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen buffer_append_c(diff_buf, -1);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen new_iov_count++;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen new_iov_size++;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen }
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (new_iov_count >= IOVBUF_COUNT-1) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ret = sendv_crlf(cstream, iov_buf->data,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen new_iov_count, diff_buf->data,
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen &total);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (ret != (ssize_t)new_iov_size) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t_pop();
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return ret < 0 ? ret : total;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen buffer_set_used_size(iov_buf, 0);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen buffer_set_used_size(diff_buf, 0);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen new_iov_count = 0;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen new_iov_size = 0;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (i == len)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen break;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (len != 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen last_cr = data[len-1] == '\r';
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = sendv_crlf(cstream, iov_buf->data, new_iov_count,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen diff_buf->data, &total);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t_pop();
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return ret < 0 ? ret : total;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic ssize_t
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainensendv_lf(struct crlf_ostream *cstream, const struct const_iovec *iov,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen size_t iov_count, const char *diff, ssize_t *total_r)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ssize_t ret;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen size_t i, left;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ret = o_stream_sendv(cstream->output, iov, iov_count);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (ret >= 0) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen left = (size_t)ret;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen for (i = 0; i < iov_count && left >= iov[i].iov_len; i++) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen *total_r += iov[i].iov_len + diff[i];
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen left -= iov[i].iov_len;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen *total_r += left;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen cstream->ostream.ostream.stream_errno = cstream->output->stream_errno;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen cstream->ostream.ostream.offset = cstream->output->offset;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return ret;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic ssize_t
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen_sendv_lf(struct _ostream *stream, const struct const_iovec *iov,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen unsigned int iov_count)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct crlf_ostream *cstream = (struct crlf_ostream *)stream;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen buffer_t *iov_buf, *diff_buf;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const unsigned char *data;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct const_iovec new_iov;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen unsigned int vec, i, len, start, next;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen unsigned int new_iov_count = 0, new_iov_size = 0;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ssize_t ret, total;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen int diff;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t_push();
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen iov_buf = buffer_create_dynamic(unsafe_data_stack_pool,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen sizeof(struct const_iovec *) *
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen IOVBUF_COUNT);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen diff_buf = buffer_create_dynamic(unsafe_data_stack_pool, IOVBUF_COUNT);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen total = 0;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen for (vec = 0; vec < iov_count; vec++) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen data = iov[vec].iov_base;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen len = iov[vec].iov_len;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen for (i = start = 0;; i++) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (i != len) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (data[i] != '\n' || i == 0 ||
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen data[i-1] != '\r')
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen continue;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (start == 0 && i > 0 && data[0] != '\n' &&
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen cstream->last_cr) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* bare CR, keep it */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen buffer_append(iov_buf, &cr_iov, sizeof(cr_iov));
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen buffer_append_c(diff_buf, -1);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen new_iov_count++;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov_size++;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen next = i;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (i != len) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* skipping an CR */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen i--;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen cstream->last_cr = FALSE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen diff = 1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else if (i != start && data[i-1] == '\r') {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* data ends with CR, don't add it yet */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen i--;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen cstream->last_cr = TRUE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen diff = 1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* data doesn't end with CR */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen cstream->last_cr = FALSE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen diff = 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov.iov_base = data + start;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov.iov_len = i - start;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen buffer_append(iov_buf, &new_iov, sizeof(new_iov));
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen buffer_append_c(diff_buf, diff);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov_count++;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov_size += new_iov.iov_len;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen start = i = next;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (new_iov_count >= IOVBUF_COUNT-1) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen ret = sendv_lf(cstream, iov_buf->data,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov_count, diff_buf->data,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen &total);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen stream->ostream.offset =
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen cstream->output->offset;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (ret != (ssize_t)new_iov_size) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen t_pop();
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return ret < 0 ? ret : total;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen buffer_set_used_size(iov_buf, 0);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen buffer_set_used_size(diff_buf, 0);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov_count = 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen new_iov_size = 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (i == len)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (new_iov_count == 0) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* Tried to send only CR. */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = 0;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen } else {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = sendv_lf(cstream, iov_buf->data, new_iov_count,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen diff_buf->data, &total);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen stream->ostream.offset = cstream->output->offset;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen t_pop();
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return ret < 0 ? ret : total;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic off_t
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen_send_istream(struct _ostream *outstream, struct istream *instream)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen struct const_iovec iov;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const unsigned char *data;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen size_t sent = 0;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ssize_t ret;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen while ((ret = i_stream_read_data(instream, &data,
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen &iov.iov_len, 0)) != -1) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (iov.iov_len == 0)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return sent;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen iov.iov_base = data;
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen ret = o_stream_sendv(&outstream->ostream, &iov, 1);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (ret <= 0)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return ret < 0 && sent == 0 ? -1 : (ssize_t)sent;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen i_assert((size_t)ret <= iov.iov_len);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen i_stream_skip(instream, ret);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen sent += ret;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if ((size_t)ret != iov.iov_len)
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen return sent;
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return sent == 0 && instream->stream_errno != 0 ? -1 : (ssize_t)sent;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen}
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainenstatic struct crlf_ostream *
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Siraineno_stream_create_common(pool_t pool, struct ostream *output)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen{
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct crlf_ostream *cstream;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream = p_new(pool, struct crlf_ostream, 1);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->output = output;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen o_stream_ref(output);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.iostream.close = _close;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.iostream.destroy = _destroy;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.iostream.set_max_buffer_size = _set_max_buffer_size;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.cork = _cork;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.flush = _flush;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.flush_pending = _flush_pending;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.get_used_size = _get_used_size;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen cstream->ostream.seek = _seek;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen cstream->ostream.send_istream = _send_istream;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return cstream;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstruct ostream *o_stream_create_crlf(pool_t pool, struct ostream *output)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen struct crlf_ostream *cstream;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen cstream = o_stream_create_common(pool, output);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen cstream->ostream.sendv = _sendv_crlf;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return _o_stream_create(&cstream->ostream, pool);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstruct ostream *o_stream_create_lf(pool_t pool, struct ostream *output)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen struct crlf_ostream *cstream;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen cstream = o_stream_create_common(pool, output);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen cstream->ostream.sendv = _sendv_lf;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return _o_stream_create(&cstream->ostream, pool);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen