Permalink
Browse files

2.4.3 release, fixing a bug with headers longer than 78 bytes contain…

…ing high-byte characters.
  • Loading branch information...
1 parent e948194 commit a3fea525ff690b94f18cdcc5fdfec4d671515984 @bertjohnson committed Jan 10, 2017
View
@@ -1,6 +1,9 @@
### Changelog ###
-2.4.2 - 2016-01-08
+2.4.3 - 2017-01-09
+ * Fixed bug when headers contained high-byte characters after the 78th index.
+
+2.4.2 - 2017-01-08
* Updated `ImapClient.GetMessagePartialHelper` to deal with situations where the body length is shorter than what is reported.
2.4.1 - 2016-12-23
@@ -25,7 +25,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bert Johnson")]
[assembly: AssemblyProduct("OpaqueMail")]
-[assembly: AssemblyCopyright("Copyright © 2013-2016 Bert Johnson")]
+[assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -47,5 +47,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.2")]
-[assembly: AssemblyFileVersion("2.4.2")]
+[assembly: AssemblyVersion("2.4.3")]
+[assembly: AssemblyFileVersion("2.4.3")]
@@ -25,7 +25,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bert Johnson")]
[assembly: AssemblyProduct("OpaqueMail")]
-[assembly: AssemblyCopyright("Copyright © 2013-2016 Bert Johnson")]
+[assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -47,5 +47,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.2")]
-[assembly: AssemblyFileVersion("2.4.2")]
+[assembly: AssemblyVersion("2.4.3")]
+[assembly: AssemblyFileVersion("2.4.3")]
@@ -24,7 +24,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bert Johnson")]
[assembly: AssemblyProduct("OpaqueMail")]
-[assembly: AssemblyCopyright("Copyright © 2013-2016 Bert Johnson")]
+[assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -46,5 +46,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.2")]
-[assembly: AssemblyFileVersion("2.4.2")]
+[assembly: AssemblyVersion("2.4.3")]
+[assembly: AssemblyFileVersion("2.4.3")]
@@ -24,7 +24,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bert Johnson")]
[assembly: AssemblyProduct("OpaqueMail")]
-[assembly: AssemblyCopyright("Copyright © 2013-2016 Bert Johnson")]
+[assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -46,5 +46,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.2")]
-[assembly: AssemblyFileVersion("2.4.2")]
+[assembly: AssemblyVersion("2.4.3")]
+[assembly: AssemblyFileVersion("2.4.3")]
@@ -24,7 +24,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bert Johnson")]
[assembly: AssemblyProduct("OpaqueMail")]
-[assembly: AssemblyCopyright("Copyright © 2013-2016 Bert Johnson")]
+[assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -46,5 +46,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.2")]
-[assembly: AssemblyFileVersion("2.4.2")]
+[assembly: AssemblyVersion("2.4.3")]
+[assembly: AssemblyFileVersion("2.4.3")]
View
@@ -38,7 +38,7 @@ PROJECT_NAME = "OpaqueMail"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 2.4.2
+PROJECT_NUMBER = 2.4.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
View
Binary file not shown.
@@ -480,23 +480,72 @@ public static string Encode(string input, string ContentTransferEncoding)
/// <returns>Base-64 encoded version of the email header.</returns>
public static string EncodeMailHeader(string header)
{
+ return EncodeMailHeader(header, -1);
+ }
+
+ /// <summary>
+ /// Encodes email headers to escape extended characters.
+ /// </summary>
+ /// <param name="header">Email header to be encoded.</param>
+ /// <param name="maxChunkSize">Maximum number of bytes in each encoded chunk.</param>
+ /// <returns>Base-64 encoded version of the email header.</returns>
+ public static string EncodeMailHeader(string header, int maxChunkSize)
+ {
if (string.IsNullOrEmpty(header))
return "";
- bool extendedCharacterFound = false;
- foreach (char headerCharacter in header.ToCharArray())
+ // If passed value is already folded, unfold it prior to encoding.
+ header = header.Replace("\r\n ", " ").Replace("\r\n\t", " ");
+
+ int lastCharacterExtendedStart = -1;
+ StringBuilder headerBuilder = new StringBuilder();
+ char[] headerCharacters = header.ToCharArray();
+ int max = headerCharacters.Length;
+ for (int i = 0; i < max; i++)
{
+ char headerCharacter = headerCharacters[i];
if (headerCharacter > 127)
{
- extendedCharacterFound = true;
- break;
+ if (lastCharacterExtendedStart < 0)
+ lastCharacterExtendedStart = i;
+ }
+ else
+ {
+ if (lastCharacterExtendedStart > -1)
+ {
+ int chunkSize = i - lastCharacterExtendedStart;
+ if (chunkSize > maxChunkSize)
+ chunkSize = maxChunkSize;
+
+ for (int j = lastCharacterExtendedStart; j < i; j += maxChunkSize)
+ {
+ if (j + chunkSize <= i)
+ headerBuilder.Append("=?UTF-8?B?" + ToBase64String(header.Substring(j, chunkSize)) + "?=");
+ else
+ headerBuilder.Append("=?UTF-8?B?" + ToBase64String(header.Substring(j)) + "?=");
+ }
+
+ lastCharacterExtendedStart = -1;
+ }
+
+ headerBuilder.Append(headerCharacter);
}
}
- if (extendedCharacterFound)
- return "=?UTF-8?B?" + ToBase64String(header) + "?=";
- else
- return header;
+ if (lastCharacterExtendedStart > -1)
+ {
+ for (int j = lastCharacterExtendedStart; j < max; j += maxChunkSize)
+ {
+ if (j + maxChunkSize <= max)
+ headerBuilder.Append("=?UTF-8?B?" + ToBase64String(header.Substring(j, maxChunkSize)) + "?=");
+ else
+ headerBuilder.Append("=?UTF-8?B?" + ToBase64String(header.Substring(j)) + "?=");
+ }
+
+ lastCharacterExtendedStart = 0;
+ }
+
+ return headerBuilder.ToString();
}
/// <summary>
@@ -1299,28 +1348,70 @@ public static void SendStreamString(StreamWriter streamWriter, string message)
/// <returns>The original email header spread over lines no longer than 78 characters each.</returns>
public static string SpanHeaderLines(string header)
{
- if (header.Length > 78)
+ return SpanHeaderLines(header, 78);
+ }
+
+ /// <summary>
+ /// Attempt to keep the number of characters per subject line to a certain number of characters.
+ /// </summary>
+ /// <param name="header">Email header to be spanned.</param>
+ /// <param name="maxLineLength">Maximum length for a line.</param>
+ /// <returns>The original email header spread over lines no longer than the number of characters specified.</returns>
+ public static string SpanHeaderLines(string header, int maxLineLength)
+ {
+ if (header.Length > maxLineLength)
{
StringBuilder headerBuilder = new StringBuilder(Constants.TINYSBSIZE);
- int pos = 0, lastPos = 0;
- while (pos > -1 && pos < header.Length - 78)
+ int pos = 0, spacePos = 0, endEncodingPos = 0, lastPos = 0;
+ while (pos > -1 && pos < header.Length - maxLineLength)
{
- if (lastPos + 78 >= header.Length)
- pos = header.LastIndexOf(" ");
+ if (lastPos + maxLineLength >= header.Length)
+ {
+ spacePos = header.LastIndexOf(" ");
+ endEncodingPos = header.LastIndexOf("?=");
+ }
else
- pos = header.LastIndexOf(" ", lastPos + 78);
+ {
+ spacePos = header.LastIndexOf(" ", lastPos + maxLineLength);
+ endEncodingPos = header.LastIndexOf("?=", lastPos + maxLineLength);
+ }
+ if (endEncodingPos == -1 || spacePos > endEncodingPos)
+ pos = spacePos;
+ else
+ pos = endEncodingPos;
if (pos < 0 || pos == (lastPos - 1))
- pos = header.IndexOf(" ", lastPos + 78);
+ pos = header.IndexOf(" ", lastPos + maxLineLength);
if (pos > -1)
{
- headerBuilder.Append(header.Substring(lastPos, pos - lastPos) + "\r\n\t");
- pos++;
+ while (pos - lastPos > maxLineLength)
+ {
+ headerBuilder.Append(header.Substring(lastPos, maxLineLength) + "\r\n ");
+
+ lastPos += maxLineLength;
+ }
+
+ headerBuilder.Append(header.Substring(lastPos, pos - lastPos) + "\r\n ");
+
+ if (pos == endEncodingPos)
+ lastPos += maxLineLength;
+ else
+ lastPos++;
}
- lastPos = pos;
+
+ if (pos > -1)
+ lastPos = pos;
+ }
+
+ pos = header.Length - 1;
+ while (pos - lastPos > maxLineLength)
+ {
+ headerBuilder.Append(header.Substring(lastPos, maxLineLength) + "\r\n ");
+ lastPos += maxLineLength;
}
+
headerBuilder.Append(header.Substring(lastPos));
return headerBuilder.ToString();
@@ -25,7 +25,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bert Johnson")]
[assembly: AssemblyProduct("OpaqueMail")]
-[assembly: AssemblyCopyright("Copyright © 2013-2016 Bert Johnson")]
+[assembly: AssemblyCopyright("Copyright © 2013-2017 Bert Johnson")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -47,5 +47,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.4.2")]
-[assembly: AssemblyFileVersion("2.4.2")]
+[assembly: AssemblyVersion("2.4.3")]
+[assembly: AssemblyFileVersion("2.4.3")]
@@ -244,7 +244,7 @@ public void Send(MailMessage message)
if (!response.StartsWith("3"))
throw new SmtpException("Exception communicating with server '" + Host + "'. Sent 'DATA' and received '" + response + "'.");
- rawHeaders.Append(Functions.SpanHeaderLines("Subject: " + Functions.EncodeMailHeader(message.Subject)) + "\r\n");
+ rawHeaders.Append(Functions.SpanHeaderLines("Subject: " + Functions.EncodeMailHeader(message.Subject, 32)) + "\r\n");
foreach (string rawHeader in message.Headers)
{
switch (rawHeader.ToUpper())
View
@@ -41,7 +41,7 @@ Created by Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://all
License
=======
-Copyright © 2013-2016 Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
+Copyright © 2013-2017 Bert Johnson (https://bertjohnson.com/) of Allcloud Inc. (https://allcloud.com/).
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

0 comments on commit a3fea52

Please sign in to comment.