Skip to content

Commit

Permalink
Improved folding logic for Disposition-Notification-Options header va…
Browse files Browse the repository at this point in the history
…lues

Fixes issue #979
  • Loading branch information
jstedfast committed Dec 3, 2023
1 parent afc6c62 commit f3b5ee2
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 4 deletions.
61 changes: 57 additions & 4 deletions MimeKit/Header.cs
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ static byte[] EncodeReceivedHeader (ParserOptions options, FormatOptions format,
{
var tokens = new List<ReceivedTokenValue> ();
var rawValue = encoding.GetBytes (value);
var encoded = new ValueStringBuilder (128);
var encoded = new ValueStringBuilder (rawValue.Length);
int lineLength = field.Length + 1;
bool date = false;
int index = 0;
Expand Down Expand Up @@ -825,7 +825,7 @@ static void EncodeDkimHeaderList (FormatOptions format, ref ValueStringBuilder e

static byte[] EncodeDkimOrArcSignatureHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value)
{
var encoded = new ValueStringBuilder (128);
var encoded = new ValueStringBuilder (value.Length);
int lineLength = field.Length + 1;
int index = 0;

Expand Down Expand Up @@ -884,9 +884,58 @@ static byte[] EncodeDkimOrArcSignatureHeader (ParserOptions options, FormatOptio
return encoding.GetBytes (encoded.ToString ());
}

static byte[] EncodeDispositionNotificationOptions (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value)
{
var encoded = new ValueStringBuilder (value.Length);
int lineLength = field.Length + 1;
int index = 0;

while (index < value.Length) {
using var parameter = new ValueStringBuilder (128);

while (index < value.Length && IsWhiteSpace (value[index]))
index++;

int startIndex = index;

while (index < value.Length && value[index] != '=') {
if (!IsWhiteSpace (value[index]))
parameter.Append (value[index]);
index++;
}

while (index < value.Length && value[index] != ';') {
if (!IsWhiteSpace (value[index]))
parameter.Append (value[index]);
index++;
}

if (index < value.Length && value[index] == ';') {
parameter.Append (';');
index++;
}

if (lineLength + parameter.Length + 1 > format.MaxLineLength && encoded.Length > 0) {
encoded.Append (format.NewLine);
encoded.Append ('\t');
lineLength = 1;
} else {
encoded.Append (' ');
lineLength++;
}

encoded.Append (parameter.AsSpan ());
lineLength += parameter.Length;
}

encoded.Append (format.NewLine);

return encoding.GetBytes (encoded.ToString ());
}

static byte[] EncodeReferencesHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value)
{
var encoded = new ValueStringBuilder (128);
var encoded = new ValueStringBuilder (value.Length);
int lineLength = field.Length + 1;
int count = 0;

Expand Down Expand Up @@ -1179,7 +1228,7 @@ static bool IsMailingListCommandSpecial (char c)

static byte[] EncodeMailingListCommandHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value)
{
var encoded = new ValueStringBuilder (128);
var encoded = new ValueStringBuilder (value.Length);
int lineLength = field.Length + 1;
int index = 0;

Expand Down Expand Up @@ -1309,6 +1358,8 @@ protected virtual byte[] FormatRawValue (FormatOptions format, Encoding encoding
return EncodeContentDisposition (Options, format, encoding, Field, value);
case HeaderId.ContentType:
return EncodeContentType (Options, format, encoding, Field, value);
case HeaderId.DispositionNotificationOptions:
return EncodeDispositionNotificationOptions (Options, format, encoding, Field, value);
case HeaderId.ArcAuthenticationResults:
case HeaderId.AuthenticationResults:
return EncodeAuthenticationResultsHeader (Options, format, encoding, Field, value);
Expand Down Expand Up @@ -1362,6 +1413,8 @@ internal byte[] GetRawValue (FormatOptions format)
return ReformatContentDisposition (Options, format, CharsetUtils.UTF8, Field, rawValue);
case HeaderId.ContentType:
return ReformatContentType (Options, format, CharsetUtils.UTF8, Field, rawValue);
case HeaderId.DispositionNotificationOptions:
return rawValue;
case HeaderId.ArcAuthenticationResults:
case HeaderId.AuthenticationResults:
// Note: No text that can be internationalized.
Expand Down
16 changes: 16 additions & 0 deletions UnitTests/HeaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -723,5 +723,21 @@ public void TestEncodeListCommandHeaderWithExtremelyLongUrl ()

Assert.AreEqual (expected.ReplaceLineEndings (), result);
}

[Test]
public void TestEncodeDispositionNotificationOptions ()
{
const string value = "signed-receipt-protocol=optional,pkcs7-signature;signed-receipt-micalg=optional,sha1,sha128,sha256";
const string expected = " signed-receipt-protocol=optional,pkcs7-signature;\r\n\tsigned-receipt-micalg=optional,sha1,sha128,sha256\r\n";
var header = new Header (HeaderId.DispositionNotificationOptions, value);

var options = FormatOptions.Default.Clone ();
options.NewLineFormat = NewLineFormat.Dos;
options.International = false;

var result = Encoding.UTF8.GetString (header.GetRawValue (options));

Assert.AreEqual (expected.ReplaceLineEndings (), result);
}
}
}

0 comments on commit f3b5ee2

Please sign in to comment.