From 0adb7400e820d3580e23eb6db5449bf4a9f58c3b Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@dovecot.fi>
Date: Fri, 19 Aug 2016 23:05:27 +0200
Subject: [PATCH] lib-sieve: util: program-client-remote: Made the
 program_client_istream implementation cleaner and more logical.

It was too hard to understand.
---
 src/lib-sieve/util/program-client-remote.c | 32 +++++++++++++---------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/lib-sieve/util/program-client-remote.c b/src/lib-sieve/util/program-client-remote.c
index 0af3fc9bb..11fa043ba 100644
--- a/src/lib-sieve/util/program-client-remote.c
+++ b/src/lib-sieve/util/program-client-remote.c
@@ -41,28 +41,31 @@ static ssize_t program_client_istream_read(struct istream_private *stream)
 	struct program_client_istream *scstream =
 		(struct program_client_istream *)stream;
 	size_t pos, reserved;
-	ssize_t ret;
+	ssize_t ret = 0;
 
 	i_stream_skip(stream->parent, stream->skip);
-	stream->pos -= stream->skip;
 	stream->skip = 0;
 
 	stream->buffer = i_stream_get_data(stream->parent, &pos);
 
+	reserved = 0;
 	if ( stream->buffer != NULL && pos >= 1 ) {
 		/* retain/hide potential return code at end of buffer */
 		reserved = ( stream->buffer[pos-1] == '\n' && pos > 1 ? 2 : 1 );
 		pos -= reserved;
 	}
 
-	if (pos > stream->pos) {
-		ret = 0;
-	} else if ( stream->parent->eof ) {
+	if ( stream->parent->eof ) {
+		if (pos == 0)
+			i_stream_skip(stream->parent, reserved);
 		stream->istream.eof = TRUE;
 		ret = -1;
 	} else do {
-		if ((ret = i_stream_read(stream->parent)) == -2)
+		if ((ret = i_stream_read(stream->parent)) == -2) {
 			return -2; /* input buffer full */
+		}
+
+		if ( ret == 0 || (ret < 0 && !stream->parent->eof) ) break;
 
 		stream->istream.stream_errno = stream->parent->stream_errno;
 		stream->buffer = i_stream_get_data(stream->parent, &pos);
@@ -88,30 +91,33 @@ static ssize_t program_client_istream_read(struct istream_private *stream)
 	
 		if ( stream->buffer != NULL && pos >= 1 ) {
 			/* retain/hide potential return code at end of buffer */
-			reserved = ( stream->buffer[pos-1] == '\n' && pos > 1 ? 2 : 1 );
+			size_t old_reserved = reserved;
+			ssize_t reserve_inc;
 
+			reserved = ( stream->buffer[pos-1] == '\n' && pos > 1 ? 2 : 1 );
+			i_assert(reserved >= old_reserved);
+			reserve_inc = reserved - old_reserved;
 			pos -= reserved;
 
-			if ( ret > 0 ) {
-				ret = ( (size_t)ret > reserved ? ret - reserved : 0 );
+			if (ret > 0) {
+				i_assert(ret >= reserve_inc);
+				ret -= reserve_inc;
 			}
 		}
 
-		if ( ret == 0 || (ret < 0 && !stream->parent->eof) ) break;
-
 		if ( ret <= 0 && stream->parent->eof ) {
 			/* Parent EOF and not more data to return; EOF here as well */
+			if (pos == 0)
+				i_stream_skip(stream->parent, reserved);
 			stream->istream.eof = TRUE;
 			ret = -1;
 		}		
 	} while ( ret == 0 );
 
- 	ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : (ret == 0 ? 0 : -1);
 	stream->pos = pos;
 
 	i_assert(ret != -1 || stream->istream.eof ||
 		stream->istream.stream_errno != 0);
-
 	return ret;
 }
 
-- 
GitLab