diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2017-12-16 22:55:31 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2017-12-16 23:18:13 +0200 |
commit | bd385c4a2d26215e080d6248435c9efe3bd1d0b1 (patch) | |
tree | d2fe1911109eae8221f7f638f5b3b2f58e845615 /imap4d | |
parent | 9d4dbe87b36ab7df8a9e00d47869ab251e404a19 (diff) | |
download | mailutils-bd385c4a2d26215e080d6248435c9efe3bd1d0b1.tar.gz mailutils-bd385c4a2d26215e080d6248435c9efe3bd1d0b1.tar.bz2 |
Fix the operation of CRLF and CRLFDOT filters.
When encoding, these filters used to retain any existing CRLF
sequences untouched on output. As a result, it was not possible to
predict the number of characters output having the number of
characters and number of lines on input. Due to this imap4d fetch
would produce invalid literal output on FETCH command if the
requested stream (usually body), contained a mixture of LF and
CRLF terminated lines. Moreover, encode + decode operations would
not be idempotent in this case.
To fix this, the default behavior of CRLF and CRLFDOT filter in
encode mode is changed to translate each LF to CRLF, no matter what
the prior character was. To invoke the former "normalizing" behavior,
the "-n" option argument is provided for mu_filter_create_args.
* imap4d/fetch.c (fetch_io): Use raw stream when possible.
Use a temporary CRLF translator to ensure proper positioning if
start offset is specified. This is suboptimal (to say the very
least) and will be fixed as soon as possible.
* imap4d/io.c (io_enable_crlf): New funcition (hopefully temporary).
* libmailutils/filter/crlfdot.c: When encoding, retain input CRLF
only if the -n option was used when creating the filter. Otherwise,
translate it to CRCRLF.
* libmailutils/filter/crlfflt.c: Likewise.
* libmailutils/stream/fltstream.c (filter_read): Make sure
mu_filter_lastbuf is always emitted prior to closing the filter.
(filter_seek): Clear flag_eof.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add dump and tocrlf.
* libmailutils/tests/crlf.at: New test case.
* libmailutils/tests/crlfdot.at: New test case.
* libmailutils/tests/dump.c: New auxiliary program.
* libmailutils/tests/tocrlf.c: Likewise.
* libmailutils/tests/testsuite.at (MU_FILTER_TEST_NIBBLE)
(MU_FILTER_TEST): New defines.
Diffstat (limited to 'imap4d')
-rw-r--r-- | imap4d/fetch.c | 33 | ||||
-rw-r--r-- | imap4d/io.c | 8 |
2 files changed, 29 insertions, 12 deletions
diff --git a/imap4d/fetch.c b/imap4d/fetch.c index 5efcda3a0..7a1912190 100644 --- a/imap4d/fetch.c +++ b/imap4d/fetch.c @@ -709,18 +709,11 @@ fetch_send_section_part (struct fetch_function_closure *ffc, static int fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max) { - mu_stream_t rfc = NULL; - - size_t n = 0; - - mu_filter_create (&rfc, stream, "CRLF", MU_FILTER_ENCODE, - MU_STREAM_READ|MU_STREAM_SEEK); - if (start == 0 && size == (size_t) -1) { int rc; - rc = mu_stream_seek (rfc, 0, MU_SEEK_SET, NULL); + rc = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL); if (rc) { mu_error ("seek error: %s", mu_stream_strerror (stream, rc)); @@ -729,7 +722,7 @@ fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max) if (max) { io_sendf (" {%lu}\n", (unsigned long) max); - io_copy_out (rfc, max); + io_copy_out (stream, max); /* FIXME: Make sure exactly max bytes were sent */ } else @@ -742,10 +735,12 @@ fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max) } else { + mu_stream_t rfc = NULL; int rc; char *buffer, *p; size_t total = 0; - + size_t n = 0; + if (size > max) size = max; if (size + 2 < size) /* Check for integer overflow */ @@ -754,6 +749,9 @@ fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max) return RESP_BAD; } + mu_filter_create (&rfc, stream, "CRLF", MU_FILTER_ENCODE, + MU_STREAM_READ|MU_STREAM_SEEK); + p = buffer = mu_alloc (size + 1); rc = mu_stream_seek (rfc, start, MU_SEEK_SET, NULL); @@ -766,24 +764,35 @@ fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max) } while (total < size - && mu_stream_read (rfc, p, size - total, &n) == 0 + && (rc = mu_stream_read (rfc, p, size - total, &n)) == 0 && n > 0) { total += n; p += n; } + + if (rc) + { + mu_error ("read error: %s", mu_stream_strerror (rfc, rc)); + free (buffer); + mu_stream_destroy (&rfc); + return RESP_BAD; + } + *p = 0; io_sendf ("<%lu>", (unsigned long) start); if (total) { io_sendf (" {%lu}\n", (unsigned long) total); + io_enable_crlf (0); io_send_bytes (buffer, total); + io_enable_crlf (1); } else io_sendf (" \"\""); free (buffer); + mu_stream_destroy (&rfc); } - mu_stream_destroy (&rfc); return RESP_OK; } diff --git a/imap4d/io.c b/imap4d/io.c index b1c1d7d04..9a2047419 100644 --- a/imap4d/io.c +++ b/imap4d/io.c @@ -727,3 +727,11 @@ imap4d_tokbuf_from_string (char *str) return tok; } +void +io_enable_crlf (int enable) +{ + enable = !enable; + mu_stream_ioctl (iostream, MU_IOCTL_FILTER, + MU_IOCTL_FILTER_SET_DISABLED, + &enable); +} |