Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mimemail: utf-8 headers with newline in them would cause a crash when encoding #246

Closed
seriyps opened this issue Feb 21, 2021 · 1 comment · Fixed by #247
Closed

mimemail: utf-8 headers with newline in them would cause a crash when encoding #246

seriyps opened this issue Feb 21, 2021 · 1 comment · Fixed by #247

Comments

@seriyps
Copy link
Collaborator

seriyps commented Feb 21, 2021

> Mail = {<<"text">>, <<"plain">>, [{<<"Subject">>, <<"Привет\nмир"/utf8>>}, {<<"From">>, <<"[email protected]">>}, {<<"Content-Type">>, <<"text/plain; charset=utf-8">>}], #{}, <<"Test">>}.
{<<"text">>,<<"plain">>,
 [{<<"Subject">>,
   <<208,159,209,128,208,184,208,178,208,181,209,130,10,208,
     188,208,184,209,128>>},
  {<<"From">>,<<"[email protected]">>},
  {<<"Content-Type">>,<<"text/plain; charset=utf-8">>}],
 #{},<<"Test">>}
> mimemail:encode(Mail).
** exception error: no function clause matching
 mimemail:rfc2047_utf8_encode([10,208,188,208,184,209,128],
                                                                             "5B=0D=2B=0D=8B=0D=08=1D=F9=0D=?Q?8-FTU?=",40,"28=1D=") (gen_smtp/src/mimemail.erl, line 964)
     in function  mimemail:encode_headers/1 (gen_smtp/src/mimemail.erl, line 788)
     in call from mimemail:encode/2 (gen_smtp/src/mimemail.erl, line 165)

here 10 is \n. I guess that's because we don't have clause for characters below 32 here, so, I guess, \t and \r would cause the same issue

gen_smtp/src/mimemail.erl

Lines 964 to 985 in 7b50cfa

rfc2047_utf8_encode(T, Acc, WordLen, Char) when WordLen + length(Char) > 73 ->
CloseLine = lists:reverse("?=\r\n "),
NewLine = Char ++ lists:reverse("=?UTF-8?Q?"),
%% Make sure that the individual encoded words are not longer than 76 chars (including charset etc)
rfc2047_utf8_encode(T, NewLine ++ CloseLine ++ Acc, length(NewLine), []);
rfc2047_utf8_encode([], Acc, _WordLen, Char) ->
lists:reverse("=?" ++ Char ++ Acc);
%% ASCII characters dont encode except space, ?, _, =, and .
rfc2047_utf8_encode([C|T], Acc, WordLen, Char) when C > 32 andalso C < 127 andalso C /= 32
andalso C /= $? andalso C /= $_ andalso C /= $= andalso C /= $. ->
rfc2047_utf8_encode(T, Char ++ Acc, WordLen+length(Char), [C]);
%% Encode all other ASCII
rfc2047_utf8_encode([C|T], Acc, WordLen, Char) when C >= 32 andalso C < 127 ->
rfc2047_utf8_encode(T, Char ++ Acc, WordLen+length(Char), encode_byte(C));
%% First byte of UTF-8 sequence
%% ensure that encoded 2-4 byte UTF-8 characters keept in one line
rfc2047_utf8_encode([C|T], Acc, WordLen, Char) when C > 192 andalso C =< 247 ->
UTFBytes = utf_char_bytes(C),
{Rest, ExtraUTFBytes} = encode_extra_utf_bytes(UTFBytes-1, T),
rfc2047_utf8_encode(Rest, Char ++ Acc, WordLen+length(Char), ExtraUTFBytes ++ encode_byte(C)).

@seriyps
Copy link
Collaborator Author

seriyps commented Feb 21, 2021

Python seems to QP-encode al lthe characters below 32, except \r and \n:

> import quopri
> quopri.encodestring(b"".join(chr(i).encode("utf8") for i in range(1, 255)))
b'=01=02=03=04=05=06=07=08=09\n=0B=0C\r=0E=0F=10=11=12=13=14=15=16=17=18=19=1A=1B=1C=1D=1E=1F !"#$%&\'()*+,-=\n./0123456789:;<=3D>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv=\nwxyz{|}~=7F=C2=80=C2=81=C2=82=C2=83=C2=84=C2=85=C2=86=C2=87=C2=88=C2=89=C2=\n=8A=C2=8B=C2=8C=C2=8D=C2=8E=C2=8F=C2=90=C2=91=C2=92=C2=93=C2=94=C2=95=C2=96=\n=C2=97=C2=98=C2=99=C2=9A=C2=9B=C2=9C=C2=9D=C2=9E=C2=9F=C2=A0=C2=A1=C2=A2=C2=\n=A3=C2=A4=C2=A5=C2=A6=C2=A7=C2=A8=C2=A9=C2=AA=C2=AB=C2=AC=C2=AD=C2=AE=C2=AF=\n=C2=B0=C2=B1=C2=B2=C2=B3=C2=B4=C2=B5=C2=B6=C2=B7=C2=B8=C2=B9=C2=BA=C2=BB=C2=\n=BC=C2=BD=C2=BE=C2=BF=C3=80=C3=81=C3=82=C3=83=C3=84=C3=85=C3=86=C3=87=C3=88=\n=C3=89=C3=8A=C3=8B=C3=8C=C3=8D=C3=8E=C3=8F=C3=90=C3=91=C3=92=C3=93=C3=94=C3=\n=95=C3=96=C3=97=C3=98=C3=99=C3=9A=C3=9B=C3=9C=C3=9D=C3=9E=C3=9F=C3=A0=C3=A1=\n=C3=A2=C3=A3=C3=A4=C3=A5=C3=A6=C3=A7=C3=A8=C3=A9=C3=AA=C3=AB=C3=AC=C3=AD=C3=\n=AE=C3=AF=C3=B0=C3=B1=C3=B2=C3=B3=C3=B4=C3=B5=C3=B6=C3=B7=C3=B8=C3=B9=C3=BA=\n=C3=BB=C3=BC=C3=BD=C3=BE'
> print(quopri.encodestring(b"".join(chr(i).encode("utf8") for i in range(1, 255))).decode('ascii'))
"""
=01=02=03=04=05=06=07=08=09
=0E=0F=10=11=12=13=14=15=16=17=18=19=1A=1B=1C=1D=1E=1F !"#$%&'()*+,-=
./0123456789:;<=3D>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuv=
wxyz{|}~=7F=C2=80=C2=81=C2=82=C2=83=C2=84=C2=85=C2=86=C2=87=C2=88=C2=89=C2=
=8A=C2=8B=C2=8C=C2=8D=C2=8E=C2=8F=C2=90=C2=91=C2=92=C2=93=C2=94=C2=95=C2=96=
=C2=97=C2=98=C2=99=C2=9A=C2=9B=C2=9C=C2=9D=C2=9E=C2=9F=C2=A0=C2=A1=C2=A2=C2=
=A3=C2=A4=C2=A5=C2=A6=C2=A7=C2=A8=C2=A9=C2=AA=C2=AB=C2=AC=C2=AD=C2=AE=C2=AF=
=C2=B0=C2=B1=C2=B2=C2=B3=C2=B4=C2=B5=C2=B6=C2=B7=C2=B8=C2=B9=C2=BA=C2=BB=C2=
=BC=C2=BD=C2=BE=C2=BF=C3=80=C3=81=C3=82=C3=83=C3=84=C3=85=C3=86=C3=87=C3=88=
=C3=89=C3=8A=C3=8B=C3=8C=C3=8D=C3=8E=C3=8F=C3=90=C3=91=C3=92=C3=93=C3=94=C3=
=95=C3=96=C3=97=C3=98=C3=99=C3=9A=C3=9B=C3=9C=C3=9D=C3=9E=C3=9F=C3=A0=C3=A1=
=C3=A2=C3=A3=C3=A4=C3=A5=C3=A6=C3=A7=C3=A8=C3=A9=C3=AA=C3=AB=C3=AC=C3=AD=C3=
=AE=C3=AF=C3=B0=C3=B1=C3=B2=C3=B3=C3=B4=C3=B5=C3=B6=C3=B7=C3=B8=C3=B9=C3=BA=
=C3=BB=C3=BC=C3=BD=C3=BE
"""

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant