Mercurial > dovecot > core-2.2
view src/lib-mail/ostream-dot.c @ 18137:3009a1a6f6d5
global: freshen copyright
Robomatically:
git ls-files | xargs perl -p -i -e 's/(\d+)-201[0-4]/$1-2015/g;s/ (201[0-4]) Dovecot/ $1-2015 Dovecot/'
Happy 2015 everyone!
Signed-off-by: Phil Carmody <phil@dovecot.fi>
author | Phil Carmody <phil@dovecot.fi> |
---|---|
date | Mon, 05 Jan 2015 22:20:10 +0200 |
parents | 2866a692ec47 |
children | ca24e6d34345 |
line wrap: on
line source
/* Copyright (c) 2013-2015 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "ostream-private.h" #include "ostream-dot.h" enum dot_ostream_state { STREAM_STATE_INIT = 0, STREAM_STATE_NONE, STREAM_STATE_CR, STREAM_STATE_CRLF, }; struct dot_ostream { struct ostream_private ostream; enum dot_ostream_state state; }; static void o_stream_dot_close(struct iostream_private *stream, bool close_parent) { struct dot_ostream *dstream = (struct dot_ostream *)stream; if (dstream->state == STREAM_STATE_CRLF) (void)o_stream_send(dstream->ostream.parent, ".\r\n", 3); else (void)o_stream_send(dstream->ostream.parent, "\r\n.\r\n", 5); (void)o_stream_flush(&dstream->ostream.ostream); if (close_parent) o_stream_close(dstream->ostream.parent); } static ssize_t o_stream_dot_sendv(struct ostream_private *stream, const struct const_iovec *iov, unsigned int iov_count) { struct dot_ostream *dstream = (struct dot_ostream *)stream; ARRAY(struct const_iovec) iov_arr; const struct const_iovec *iov_new; size_t max_bytes, sent, added; unsigned int count, i; ssize_t ret; if ((ret=o_stream_flush(stream->parent)) <= 0) { /* error / we still couldn't flush existing data to parent stream. */ o_stream_copy_error_from_parent(stream); return ret; } /* check for dots */ t_array_init(&iov_arr, iov_count + 32); max_bytes = o_stream_get_buffer_avail_size(stream->parent); // FIXME: what if max_buffer_size is 0? sent = added = 0; for (i = 0; i < iov_count && max_bytes > 0; i++) { size_t size = iov[i].iov_len, chunk; const char *data = iov[i].iov_base, *p, *pend; struct const_iovec iovn; p = data; pend = CONST_PTR_OFFSET(data, size); for (; p < pend && (size_t)(p-data) < (max_bytes-2); p++) { char add = 0; switch (dstream->state) { /* none */ case STREAM_STATE_NONE: switch (*p) { case '\n': dstream->state = STREAM_STATE_CRLF; /* add missing CR */ add = '\r'; break; case '\r': dstream->state = STREAM_STATE_CR; break; } break; /* got CR */ case STREAM_STATE_CR: switch (*p) { case '\r': break; case '\n': dstream->state = STREAM_STATE_CRLF; break; default: dstream->state = STREAM_STATE_NONE; break; } break; /* got CRLF, or the first line */ case STREAM_STATE_INIT: case STREAM_STATE_CRLF: switch (*p) { case '\r': dstream->state = STREAM_STATE_CR; break; case '\n': dstream->state = STREAM_STATE_CRLF; /* add missing CR */ add = '\r'; break; case '.': /* add dot */ add = '.'; default: dstream->state = STREAM_STATE_NONE; break; } break; } if (add != 0) { chunk = (size_t)(p - data); if (chunk > 0) { /* forward chunk to new iovec */ iovn.iov_base = data; iovn.iov_len = chunk; array_append(&iov_arr, &iovn, 1); data = p; max_bytes -= chunk; sent += chunk; } /* insert byte (substitute one with pair) */ data++; iovn.iov_base = (add == '\r' ? "\r\n" : ".."); iovn.iov_len = 2; array_append(&iov_arr, &iovn, 1); max_bytes -= 2; added++; sent++; } } if (max_bytes == 0) break; chunk = ((size_t)(p-data) >= (max_bytes-2) ? max_bytes - 2 : (size_t)(p - data)); if (chunk > 0) { iovn.iov_base = data; iovn.iov_len = chunk; array_append(&iov_arr, &iovn, 1); max_bytes -= chunk; sent += chunk; } } /* send */ iov_new = array_get(&iov_arr, &count); if (count == 0) { ret = 0; } else if ((ret=o_stream_sendv(stream->parent, iov_new, count)) <= 0) { i_assert(ret < 0); o_stream_copy_error_from_parent(stream); return -1; } /* all must be sent */ i_assert((size_t)ret == sent + added); stream->ostream.offset += sent; return sent; } struct ostream * o_stream_create_dot(struct ostream *output) { struct dot_ostream *dstream; dstream = i_new(struct dot_ostream, 1); dstream->ostream.sendv = o_stream_dot_sendv; dstream->ostream.iostream.close = o_stream_dot_close; dstream->ostream.max_buffer_size = output->real_stream->max_buffer_size; return o_stream_create(&dstream->ostream, output, o_stream_get_fd(output)); }