dovecot-2.2: lib-mail: ostream-dot API changes
dovecot at dovecot.org
dovecot at dovecot.org
Sun Feb 15 08:11:30 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/ca24e6d34345
changeset: 18253:ca24e6d34345
user: Timo Sirainen <tss at iki.fi>
date: Sun Feb 15 10:03:10 2015 +0200
description:
lib-mail: ostream-dot API changes
The dot-line sending is now done when o_stream_flush() is called. This
should be used instead of relying on close() doing it, because it still
needs to write a few bytes and there are no guarantees that the parent
stream allows sending them.
Also added force_extra_crlf parameter, which specifies whether CRLF should
always be written before the dot-line, even when it already contained CRLF.
This is useful if the input is read with
i_stream_create_dot(send_last_lf=FALSE), since it allows sending a stream
that doesn't have to end with LF.
diffstat:
src/lib-mail/ostream-dot.c | 55 +++++++++++++++++++++++++++++++++-------
src/lib-mail/ostream-dot.h | 12 ++++++--
src/lib-mail/test-ostream-dot.c | 3 +-
3 files changed, 56 insertions(+), 14 deletions(-)
diffs (151 lines):
diff -r 42b3ac799f2f -r ca24e6d34345 src/lib-mail/ostream-dot.c
--- a/src/lib-mail/ostream-dot.c Sun Feb 15 09:55:56 2015 +0200
+++ b/src/lib-mail/ostream-dot.c Sun Feb 15 10:03:10 2015 +0200
@@ -10,25 +10,52 @@
STREAM_STATE_NONE,
STREAM_STATE_CR,
STREAM_STATE_CRLF,
+ STREAM_STATE_DONE
};
struct dot_ostream {
struct ostream_private ostream;
enum dot_ostream_state state;
+ bool force_extra_crlf;
};
-static void
-o_stream_dot_close(struct iostream_private *stream,
- bool close_parent)
+static int
+o_stream_dot_flush(struct ostream_private *stream)
{
struct dot_ostream *dstream = (struct dot_ostream *)stream;
+ int ret;
- 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 (o_stream_get_buffer_avail_size(stream->parent) < 5) {
+ /* make space for the dot line */
+ if ((ret = o_stream_flush(stream->parent)) <= 0) {
+ if (ret < 0)
+ o_stream_copy_error_from_parent(stream);
+ return ret;
+ }
+ }
+
+ if (dstream->state == STREAM_STATE_DONE)
+ ;
+ else if (dstream->state == STREAM_STATE_CRLF &&
+ !dstream->force_extra_crlf) {
+ ret = o_stream_send(stream->parent, ".\r\n", 3);
+ i_assert(ret == 3);
+ } else {
+ ret = o_stream_send(stream->parent, "\r\n.\r\n", 5);
+ i_assert(ret == 5);
+ }
+ dstream->state = STREAM_STATE_DONE;
+
+ if ((ret = o_stream_flush(stream->parent)) < 0)
+ o_stream_copy_error_from_parent(stream);
+ return ret;
+}
+
+static void
+o_stream_dot_close(struct iostream_private *stream, bool close_parent)
+{
+ struct dot_ostream *dstream = (struct dot_ostream *)stream;
if (close_parent)
o_stream_close(dstream->ostream.parent);
@@ -45,6 +72,8 @@
unsigned int count, i;
ssize_t ret;
+ i_assert(dstream->state != STREAM_STATE_DONE);
+
if ((ret=o_stream_flush(stream->parent)) <= 0) {
/* error / we still couldn't flush existing data to
parent stream. */
@@ -54,7 +83,9 @@
/* 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?
+ max_bytes = o_stream_get_buffer_avail_size(stream->parent);
+ i_assert(max_bytes > 0); /* FIXME: not supported currently */
+
sent = added = 0;
for (i = 0; i < iov_count && max_bytes > 0; i++) {
size_t size = iov[i].iov_len, chunk;
@@ -113,6 +144,8 @@
break;
}
break;
+ case STREAM_STATE_DONE:
+ i_unreached();
}
if (add != 0) {
@@ -168,13 +201,15 @@
}
struct ostream *
-o_stream_create_dot(struct ostream *output)
+o_stream_create_dot(struct ostream *output, bool force_extra_crlf)
{
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.flush = o_stream_dot_flush;
dstream->ostream.max_buffer_size = output->real_stream->max_buffer_size;
+ dstream->force_extra_crlf = force_extra_crlf;
return o_stream_create(&dstream->ostream, output, o_stream_get_fd(output));
}
diff -r 42b3ac799f2f -r ca24e6d34345 src/lib-mail/ostream-dot.h
--- a/src/lib-mail/ostream-dot.h Sun Feb 15 09:55:56 2015 +0200
+++ b/src/lib-mail/ostream-dot.h Sun Feb 15 10:03:10 2015 +0200
@@ -2,8 +2,14 @@
#define OSTREAM_DOT_H
/* Create output stream for writing SMTP DATA style message: Add additional "."
- to lines beginning with it. Write line that contains only "." upon close().
- */
-struct ostream *o_stream_create_dot(struct ostream *output);
+ to lines that start with ".". Write a line that contains only "." upon
+ o_stream_flush(). (This is also called at close(), but it shouldn't be
+ relied on since it could fail due to output buffer being full.)
+
+ If output ends with CRLF, force_extra_crlf controls whether additional CRLF
+ is written before the "." line. This parameter should match
+ i_stream_create_dot()'s send_last_lf parameter (reversed). */
+struct ostream *o_stream_create_dot(struct ostream *output,
+ bool force_extra_crlf);
#endif
diff -r 42b3ac799f2f -r ca24e6d34345 src/lib-mail/test-ostream-dot.c
--- a/src/lib-mail/test-ostream-dot.c Sun Feb 15 09:55:56 2015 +0200
+++ b/src/lib-mail/test-ostream-dot.c Sun Feb 15 10:03:10 2015 +0200
@@ -26,7 +26,7 @@
output_data = buffer_create_dynamic(pool_datastack_create(), 1024);
test_output = o_stream_create_buffer(output_data);
- output = o_stream_create_dot(test_output);
+ output = o_stream_create_dot(test_output, FALSE);
while ((ret = i_stream_read(test_input)) > 0 || ret == -2) {
data = i_stream_get_data(test_input, &size);
@@ -39,6 +39,7 @@
test_assert(test_input->eof);
+ test_assert(o_stream_flush(output) > 0);
o_stream_unref(&output);
o_stream_unref(&test_output);
More information about the dovecot-cvs
mailing list