From 07f2d294d451cac520438a8592cb1e9ae14b8040 Mon Sep 17 00:00:00 2001 From: Andrew Timberlake Date: Fri, 23 Aug 2024 15:53:12 +0200 Subject: [PATCH] Fix 8-bit decoding to preserve line breaks but restore wrapped lines --- lib/mail/encoders/eight_bit.ex | 19 ++++++++++++------- test/mail/encoders/eight_bit_test.exs | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/mail/encoders/eight_bit.ex b/lib/mail/encoders/eight_bit.ex index cee5812..e6f4e45 100644 --- a/lib/mail/encoders/eight_bit.ex +++ b/lib/mail/encoders/eight_bit.ex @@ -37,14 +37,19 @@ defmodule Mail.Encoders.EightBit do @doc """ Decodes an 8-bit encoded string. """ - def decode(string), do: do_decode(string, "") - defp do_decode(<<>>, acc), do: acc + def decode(encoded_string), do: do_decode(encoded_string, "", 0) - defp do_decode(<>, acc) do - {decoded, tail} = decode_char(head, tail) - do_decode(tail, acc <> decoded) + defp do_decode(<<>>, acc, _line_length), do: acc + + defp do_decode(<<"\r\n", tail::binary>>, acc, 998) do + do_decode(tail, acc, 0) + end + + defp do_decode(<>, acc, line_length) do + {decoded, tail, length} = decode_char(head, tail) + do_decode(tail, acc <> decoded, line_length + length) end - defp decode_char(?\r, <>), do: {"", tail} - defp decode_char(char, <>), do: {<>, tail} + defp decode_char(?\0, _tail), do: raise(ArgumentError, message: "illegal NUL character") + defp decode_char(char, <>), do: {<>, tail, 1} end diff --git a/test/mail/encoders/eight_bit_test.exs b/test/mail/encoders/eight_bit_test.exs index d596f54..836ccb5 100644 --- a/test/mail/encoders/eight_bit_test.exs +++ b/test/mail/encoders/eight_bit_test.exs @@ -23,8 +23,21 @@ defmodule Mail.Encoders.EightBitTest do assert Mail.Encoders.EightBit.decode("") == "" end - test "decode removes pairs" do + test "decode preserves pairs" do message = "This is a \r\ntest\r\n" - assert Mail.Encoders.EightBit.decode(message) == "This is a test" + assert Mail.Encoders.EightBit.decode(message) == "This is a \r\ntest\r\n" + end + + test "decode removes crlf wrapping characters" do + message = String.duplicate("-", 1000) + encoded = Mail.Encoders.EightBit.encode(message) + assert binary_part(encoded, 998, 2) == "\r\n" + assert message == Mail.Encoders.EightBit.decode(encoded) + end + + test "decode raises if any character is " do + assert_raise ArgumentError, fn -> + Mail.Encoders.EightBit.decode("\0") + end end end