Skip to content

Commit

Permalink
Fix issue with date parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Kees van Spelde committed Jun 26, 2024
1 parent 1fc48f5 commit 1fc4d4a
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 37 deletions.
19 changes: 8 additions & 11 deletions MsgReaderCore/Mime/Decode/Rfc2822DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal static class Rfc2822DateTime

#region Fields
/// <summary>
/// Custom DateTime formats - will be tried if cannot parse the dateInput string using the default method
/// Custom DateTime formats - will be tried if we cannot parse the dateInput string using the default method
/// Specified using formats at http://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx
/// One format per string in the array
/// </summary>
Expand Down Expand Up @@ -78,13 +78,11 @@ public static DateTime StringToDate(string inputDate)
}
catch (FormatException e) // Convert.ToDateTime() Failure
{
throw new ArgumentException(
"Could not parse date: " + e.Message + ". Input was: \"" + inputDate + "\"", e);
throw new ArgumentException($"Could not parse date: {e.Message}. Input was: \"{inputDate}\"", e);
}
catch (ArgumentException e)
{
throw new ArgumentException(
"Could not parse date: " + e.Message + ". Input was: \"" + inputDate + "\"", e);
throw new ArgumentException($"Could not parse date: {e.Message}. Input was: \"{inputDate}\"", e);
}
}
#endregion
Expand All @@ -96,7 +94,7 @@ public static DateTime StringToDate(string inputDate)
/// </summary>
/// <param name="dateTime">The date to alter</param>
/// <param name="dateInput">The input date, in which the timezone can be found</param>
/// <returns>An date altered according to the timezone</returns>
/// <returns>A date altered according to the timezone</returns>
private static DateTime AdjustTimezone(DateTime dateTime, string dateInput)
{
// We know that the timezones are always in the last part of the date input
Expand Down Expand Up @@ -314,17 +312,16 @@ private static DateTime ExtractDateTime(string dateInput)
const string time = @"\d?\d:\d?\d(:\d?\d)?";

// Correct format is 21 Nov 1997 09:55:06
const string correctFormat = @"\d\d? .+ " + year + " " + time;
const string correctFormat = $@"\d\d? [^\d]+ {year} {time}";

// Some uses incorrect format: 2012-1-1 12:30
const string incorrectFormat = year + @"-\d?\d-\d?\d " + time;
const string incorrectFormat = $@"{year}-\d?\d-\d?\d {time}";

// Some uses incorrect format: 08-May-2012 16:52:30 +0100
const string correctFormatButWithDashes = @"\d\d?-[A-Za-z]{3}-" + year + " " + time;
const string correctFormatButWithDashes = $@"\d\d?-[A-Za-z]{{3}}-{year} {time}";

// We allow both correct and incorrect format
const string joinedFormat =
@"(" + correctFormat + ")|(" + incorrectFormat + ")|(" + correctFormatButWithDashes + ")";
const string joinedFormat = $@"({correctFormat})|({incorrectFormat})|({correctFormatButWithDashes})";

var match = Regex.Match(dateInput, joinedFormat);
if (match.Success)
Expand Down
20 changes: 7 additions & 13 deletions MsgReaderCore/Mime/Header/HeaderFieldParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public static ContentType ParseContentType(string headerValue)

#region ParseContentDisposition
/// <summary>
/// Parses a the value for the header Content-Disposition to a <see cref="ContentDisposition" /> object.
/// Parses the value for the header Content-Disposition to a <see cref="ContentDisposition" /> object.
/// </summary>
/// <param name="headerValue">The value to be parsed</param>
/// <returns>A <see cref="ContentDisposition" /> object</returns>
Expand Down Expand Up @@ -210,7 +210,7 @@ public static ContentDisposition ParseContentDisposition(string headerValue)
break;

// The correct name of the parameter is filename, but some emails also contains the parameter
// name, which also holds the name of the file. Therefore we use both names for the same field.
// name, which also holds the name of the file. Therefore, we use both names for the same field.
case "NAME":
case "FILENAME":
case "REMOTE-IMAGE":
Expand All @@ -219,24 +219,18 @@ public static ContentDisposition ParseContentDisposition(string headerValue)
break;

case "CREATION-DATE":
// Notice that we need to create a new DateTime because of a failure in .NET 2.0.
// The failure is: you cannot give contentDisposition a DateTime with a Kind of UTC
// It will set the CreationDate correctly, but when trying to read it out it will throw an exception.
// It is the same with ModificationDate and ReadDate.
// This is fixed in 4.0 - maybe in 3.0 too.
// Therefore we create a new DateTime which have a DateTimeKind set to unspecified
var creationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks);
var creationDate = Rfc2822DateTime.StringToDate(value);
contentDisposition.CreationDate = creationDate;
break;

case "MODIFICATION-DATE":
case "MODIFICATION-DATE-PARM":
var modificationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks);
var modificationDate = Rfc2822DateTime.StringToDate(value);
contentDisposition.ModificationDate = modificationDate;
break;

case "READ-DATE":
var readDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks);
var readDate = Rfc2822DateTime.StringToDate(value);
contentDisposition.ReadDate = readDate;
break;

Expand All @@ -254,7 +248,7 @@ public static ContentDisposition ParseContentDisposition(string headerValue)

default:
if (!key.StartsWith("X-"))
throw new ArgumentException("Unknown parameter in Content-Disposition. Ask developer to fix! Parameter: " + key);
throw new ArgumentException($"Unknown parameter in Content-Disposition. Ask developer to fix! Parameter: {key}");
contentDisposition.Parameters.Add(key, value);
break;
}
Expand Down Expand Up @@ -294,7 +288,7 @@ public static List<string> ParseMultipleIDs(string headerValue)
// Split the string by >
// We cannot use ' ' (space) here since this is a possible value:
// <[email protected]><[email protected]>
var ids = headerValue.Trim().Split(new[] { '>' }, StringSplitOptions.RemoveEmptyEntries);
var ids = headerValue.Trim().Split(['>'], StringSplitOptions.RemoveEmptyEntries);
return ids.Select(ParseId).ToList();
}
#endregion
Expand Down
22 changes: 11 additions & 11 deletions MsgReaderCore/Mime/Header/MessageHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,15 +249,15 @@ internal MessageHeader(NameValueCollection headers)
// Create empty lists as defaults. We do not like null values
// List with an initial capacity set to zero will be replaced
// when a corresponding header is found
To = new List<RfcMailAddress>(0);
Cc = new List<RfcMailAddress>(0);
Bcc = new List<RfcMailAddress>(0);
Received = new List<Received>();
Keywords = new List<string>();
InReplyTo = new List<string>(0);
References = new List<string>(0);
DispositionNotificationTo = new List<RfcMailAddress>();
UnknownHeaders = new NameValueCollection();
To = [];
Cc = [];
Bcc = [];
Received = [];
Keywords = [];
InReplyTo = [];
References = [];
DispositionNotificationTo = [];
UnknownHeaders = [];

// Default importance type is Normal (assumed if not set)
Importance = MailPriority.Normal;
Expand Down Expand Up @@ -361,7 +361,6 @@ private void ParseHeader(string headerName, string headerValue)
case "KEYWORDS":
var keywordsTemp = headerValue.Split(',');
foreach (var keyword in keywordsTemp)
// Remove the quotes if there is any
Keywords.Add(Utility.RemoveQuotesIfAny(keyword.Trim()));
break;

Expand Down Expand Up @@ -418,7 +417,8 @@ private void ParseHeader(string headerName, string headerValue)
// See https://tools.ietf.org/html/rfc4021#section-2.1.48
case "DELIVERY-DATE":
Date = headerValue.Trim();
DateSent = Rfc2822DateTime.StringToDate(headerValue);
var date = Rfc2822DateTime.StringToDate(headerValue);
DateSent = date != DateTime.MinValue ? date : DateTime.UtcNow;
break;

// See http://tools.ietf.org/html/rfc2045#section-6
Expand Down
4 changes: 3 additions & 1 deletion MsgReaderCore/Mime/Header/Received.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ public Received(string headerValue)
if (headerValue.Contains(";"))
{
var datePart = headerValue.Substring(headerValue.LastIndexOf(";", StringComparison.Ordinal) + 1);
Date = Rfc2822DateTime.StringToDate(datePart);
var temp = Rfc2822DateTime.StringToDate(datePart);
if (temp != DateTime.MinValue)
Date = temp;
}

Names = ParseDictionary(headerValue);
Expand Down
2 changes: 1 addition & 1 deletion MsgReaderCore/MsgReader.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,7 @@
<see langword="false" /> if only headers should be parsed out of the <paramref name="rawMessageContent" /> byte
array
</param>
<param name="parseHeaders"></param>
<param name="insideSMIMEPart"></param>
</member>
<member name="M:MsgReader.Mime.Message.ProcessSignedContent(System.Byte[])">
<summary>
Expand Down

0 comments on commit 1fc4d4a

Please sign in to comment.