istream-crlf.c revision 1a266561b099269bef75eee1a3742e61130ef780
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen#include "istream-internal.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "istream-crlf.h"
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstruct crlf_istream {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct istream_private istream;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct istream *input;
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen char last_char;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen unsigned int crlf:1;
18565c69efcd7db003dbf27cf625ed822e889fb1Timo Sirainen};
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic void i_stream_crlf_destroy(struct iostream_private *stream)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct crlf_istream *cstream = (struct crlf_istream *)stream;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_free(cstream->istream.w_buffer);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen i_stream_unref(&cstream->input);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic void
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Siraineni_stream_crlf_set_max_buffer_size(struct iostream_private *stream,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen size_t max_size)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen{
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct crlf_istream *cstream = (struct crlf_istream *)stream;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen cstream->istream.max_buffer_size = max_size;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen i_stream_set_max_buffer_size(cstream->input, max_size);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen}
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic ssize_t i_stream_crlf_read(struct istream_private *stream)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen struct crlf_istream *cstream = (struct crlf_istream *)stream;
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen const unsigned char *data;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen size_t i, dest, size;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ssize_t ret;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen data = i_stream_get_data(cstream->input, &size);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (size == 0) {
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen ret = i_stream_read(cstream->input);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (ret <= 0 && (ret != -2 || stream->skip == 0)) {
4b41116563110d00330896a568eff1078c382827Timo Sirainen stream->istream.stream_errno =
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen cstream->input->stream_errno;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen stream->istream.eof = cstream->input->eof;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return ret;
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen }
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen data = i_stream_get_data(cstream->input, &size);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen i_assert(size != 0);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen }
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen if (!i_stream_get_buffer_space(stream, size, NULL))
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen return -2;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen /* @UNSAFE */
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen dest = stream->pos;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (data[0] == '\n')
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen i = 0;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen else {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (cstream->last_char == '\r') {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen /* CR without LF */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen stream->w_buffer[dest++] = '\r';
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (dest == stream->buffer_size) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen cstream->last_char = 0;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return 1;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen }
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (data[0] != '\r')
d22301419109ed4a38351715e6760011421dadecTimo Sirainen stream->w_buffer[dest++] = data[0];
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen i = 1;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen }
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen cstream->last_char = data[size-1];
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen for (; i < size && dest < stream->buffer_size; i++) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (data[i] <= '\r') {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (data[i] == '\n') {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (cstream->crlf) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (dest + 1 == stream->buffer_size)
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen break;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen stream->w_buffer[dest++] = '\r';
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen }
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen stream->w_buffer[dest++] = '\n';
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen continue;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen }
597dce34068d603fb759b4dff404b34049213e51Timo Sirainen if (data[i] == '\r' && data[i-1] != '\r')
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen continue;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (data[i-1] == '\r') {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen /* CR without LF */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen stream->w_buffer[dest++] = '\r';
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (dest == stream->buffer_size) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen cstream->last_char = 0;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen break;
4b41116563110d00330896a568eff1078c382827Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (data[i] == '\r')
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen continue;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen stream->w_buffer[dest++] = data[i];
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen i_stream_skip(cstream->input, i);
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen ret = dest - stream->pos;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (ret == 0) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen i_assert(cstream->last_char == '\r' && size == 1);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return i_stream_crlf_read(stream);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen }
4b41116563110d00330896a568eff1078c382827Timo Sirainen stream->pos = dest;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic void ATTR_NORETURN
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Siraineni_stream_crlf_seek(struct istream_private *stream ATTR_UNUSED,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen uoff_t v_offset ATTR_UNUSED, bool mark ATTR_UNUSED)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_panic("crlf-istream: seeking unsupported currently");
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic const struct stat *
4b41116563110d00330896a568eff1078c382827Timo Siraineni_stream_crlf_stat(struct istream_private *stream, bool exact)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct crlf_istream *cstream = (struct crlf_istream *)stream;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen return i_stream_stat(cstream->input, exact);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen}
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainenstatic struct istream *
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Siraineni_stream_create_crlf_full(struct istream *input, bool crlf)
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct crlf_istream *cstream;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_stream_ref(input);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream = i_new(struct crlf_istream, 1);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->input = input;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->crlf = crlf;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cstream->istream.iostream.destroy = i_stream_crlf_destroy;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->istream.iostream.set_max_buffer_size =
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_stream_crlf_set_max_buffer_size;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->istream.read = i_stream_crlf_read;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->istream.seek = i_stream_crlf_seek;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->istream.stat = i_stream_crlf_stat;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->istream.istream.blocking = input->blocking;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cstream->istream.istream.seekable = input->seekable;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return i_stream_create(&cstream->istream, i_stream_get_fd(input), 0);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen}
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainenstruct istream *i_stream_create_crlf(struct istream *input)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen{
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen return i_stream_create_crlf_full(input, TRUE);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainenstruct istream *i_stream_create_lf(struct istream *input)
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen{
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen return i_stream_create_crlf_full(input, FALSE);
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen}
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen