public void TestInvalidDateThrowsArgumentException() { Assert.Throws <ArgumentException>(() => Rfc2822DateTime.StringToDate("Sun, 03 Mar 2011 00:77:00 -0000")); Assert.Throws <ArgumentException>(() => Rfc2822DateTime.StringToDate("Sun, 03 Mar 2011 77:00:00 -0000")); Assert.Throws <ArgumentException>(() => Rfc2822DateTime.StringToDate("Sun, 43 Mar 2011 00:00:00 -0000")); Assert.Throws <ArgumentException>(() => Rfc2822DateTime.StringToDate("Sun, 43 Mar 2011 77:77:77 -9999")); }
public void TestInvalidDateReturnsMinDate() { Assert.AreEqual(DateTime.MinValue, Rfc2822DateTime.StringToDate("Sun, 03 Mar 2011 00:77:00 -0000")); Assert.AreEqual(DateTime.MinValue, Rfc2822DateTime.StringToDate("Sun, 03 Mar 2011 77:00:00 -0000")); Assert.AreEqual(DateTime.MinValue, Rfc2822DateTime.StringToDate("Sun, 43 Mar 2011 00:00:00 -0000")); Assert.AreEqual(DateTime.MinValue, Rfc2822DateTime.StringToDate("Sun, 43 Mar 2011 77:77:77 -9999")); }
public void TestEmptyCustomFormats() { Rfc2822DateTime.CustomDateTimeFormats = new string[0]; Assert.AreEqual(DateTime.MinValue, Rfc2822DateTime.StringToDate("test")); //Reset the custom formats Rfc2822DateTime.CustomDateTimeFormats = null; }
public void TestCustomFormatHandlesStringTimezone() { Rfc2822DateTime.CustomDateTimeFormats = new string[] { "ddd, dd MM yyyy HH:mm:ss" }; Assert.AreEqual(new DateTime(2014, 08, 25, 15, 34, 22), Rfc2822DateTime.StringToDate("Mon, 25 08 2014 09:34:22 CST")); //Reset the custom formats Rfc2822DateTime.CustomDateTimeFormats = null; }
public void TestUnparsableReturnsMinDate() { const string inputDate = "foo"; DateTime expectedOutput = DateTime.MinValue; DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void TestInvalidDateTimeWithYearAtTheEnd() { const string inputDate = "Tue Feb 18 10:23:30 2014 (MSK)"; DateTime expectedOutput = new DateTime(2014, 2, 18, 6, 23, 30, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void TestUnparseableDateWillNotThrowWhenAdjustingTimezone() { const string inputDate = "Fri, 19 Oct2012 13:59:12 +0200"; DateTime expectedOutput = DateTime.MinValue; DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void IllegalButStandardFormatWithDashes2() { const string inputDate = "03-jAN-2011 13:13:13 -0200"; DateTime expectedOutput = new DateTime(2011, 1, 3, 15, 13, 13, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void IllegalButStandardFormatWithDashes() { const string inputDate = "08-May-2012 16:52:30 +0100"; DateTime expectedOutput = new DateTime(2012, 5, 8, 15, 52, 30, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void OnlineExample() { const string inputDate = "Wed, 9 May 2007 12:39:13 -0500 (CDT)"; DateTime expectedOutput = new DateTime(2007, 5, 9, 17, 39, 13, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void RfcExample2() { const string inputDate = "Tue, 1 Jul 2003 10:52:37 +0200"; // +0200 we need to substract 2 hours when in UTC DateTime expectedOutput = new DateTime(2003, 7, 1, 8, 52, 37, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void ObsoleteFormatWithWhitespaceAndComment() { const string inputDate = "Fri, 21 Nov 1997 09(comment): 55 : 06 -0600"; // -0600 we need to add 6 hours when in UTC DateTime expectedOutput = new DateTime(1997, 11, 21, 15, 55, 06, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void DateWithNoSeconds() { const string inputDate = "20 Apr 1988 18:10 +0133"; // +0133 we need to substract 1 hour and 33 minutes when in UTC DateTime expectedOutput = new DateTime(1988, 4, 20, 16, 37, 00, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void ObsoleteFormatWithLotsOfWhitespaceAndComments() { const string inputDate = "(comment) (comment) 20(comment) \t Apr(comment) 1988(comment) \t18(comment) :(comment) \t 10(comment) \t +0133 (comment) \t"; // +0133 we need to substract 1 hour and 33 minutes when in UTC DateTime expectedOutput = new DateTime(1988, 4, 20, 16, 37, 00, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void ObsoleteFormat() { const string inputDate = "21 Nov 97 09:55:06 GMT"; // GMT = UTC DateTime expectedOutput = new DateTime(1997, 11, 21, 09, 55, 06, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void TestInvalidWeekdayIgnored() { // This is actually an illigal date - 08 mar is a tuesday! const string inputDate = "Sun, 08 Mar 2011 16:16:13 -0000"; DateTime expectedOutput = new DateTime(2011, 3, 8, 16, 16, 13, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void NestedComments() { const string inputDate = "Fri, 21 Nov (foo (bar (baz) ) ) 1997 09:55:06 -0600"; // -0600 we need to add 6 hours when in UTC DateTime expectedOutput = new DateTime(1997, 11, 21, 15, 55, 06, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void MilitaryTimeJ() { const string inputDate = "Wed, 9 May 2007 12:39:13 J"; // J is not a military time // Therefore it will be interpreted as -0000 DateTime expectedOutput = new DateTime(2007, 5, 9, 12, 39, 13, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void TestWrongFormatParsesTimeWithOneDigit() { // This is a valid date, but in a incorrect format const string inputDate = "1997-11-21 9:5:6 -0600"; // -0600 we need to add 6 hours when in UTC DateTime expectedOutput = new DateTime(1997, 11, 21, 15, 5, 6, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void TestCanHandleInvalidTimezone() { // This is actually an illigal date const string inputDate = "Tue, 08 Mar 2011 07:24:27 0"; // Expect -0000 used as timezone instead DateTime expectedOutput = new DateTime(2011, 3, 8, 7, 24, 27, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void MilitaryTimeZ() { const string inputDate = "Wed, 9 May 2007 12:39:13 Z"; // Z is equivalent to +0000 const string inputDateEquivalent = "Wed, 9 May 2007 12:39:13 +0000"; DateTime inputDateTime = Rfc2822DateTime.StringToDate(inputDate); DateTime inputDateTimeEquivalent = Rfc2822DateTime.StringToDate(inputDateEquivalent); Assert.AreEqual(inputDateTime, inputDateTimeEquivalent); }
public void TestDateWithOnlyOneDigitForSecond() { // This is actually an illigal string // But such a string was met, and therefore a robust parser should be able to parse it // The RFC states that 2 digits must be used for seconds const string inputDate = "Wed, 16 Mar 2011 01:03:1 +0000"; DateTime expectedOutput = new DateTime(2011, 3, 16, 1, 3, 1, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
public void UsTimeZoneUt() { const string inputDate = "Wed, 9 May 2007 12:39:13 UT"; // UT is equivalent to +0000 const string inputDateEquivalent = "Wed, 9 May 2007 12:39:13 +0000"; DateTime inputDateTime = Rfc2822DateTime.StringToDate(inputDate); DateTime inputDateTimeEquivalent = Rfc2822DateTime.StringToDate(inputDateEquivalent); Assert.AreEqual(inputDateTime, inputDateTimeEquivalent); }
public void DateWithNoSpace() { // This is actually an illigal string // But such a string was met, and therefore a robust parser should // be able to parse it const string inputDate = "19 Jan 2011 13:24:54+0000"; DateTime expectedOutput = new DateTime(2011, 1, 19, 13, 24, 54, DateTimeKind.Utc); DateTime output = Rfc2822DateTime.StringToDate(inputDate); Assert.AreEqual(expectedOutput, output); }
/// <summary> /// Parses a Received header value. /// </summary> /// <param name="headerValue">The value for the header to be parsed</param> /// <exception cref="ArgumentNullException"><exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception></exception> public Received(string headerValue) { // Remember the raw input if someone whishes to use it Raw = headerValue ?? throw new ArgumentNullException(nameof(headerValue)); // Default Date value Date = DateTime.MinValue; // The date part is the last part of the string, and is preceeded by a semicolon // Some emails forgets to specify the date, therefore we need to check if it is there if (headerValue.Contains(";")) { string datePart = headerValue.Substring(headerValue.LastIndexOf(";", StringComparison.Ordinal) + 1); Date = Rfc2822DateTime.StringToDate(datePart); } Names = ParseDictionary(headerValue); }
private DateTime GetDateHome() { String lDate = Date.Trim(); Int32 lIndex = lDate.IndexOf('('); if (lIndex >= 0) { lDate = lDate.Substring(0, lIndex).Trim(); } Rfc2822DateTime.StringToDate(lDate); // TODO review /*try * { * return System.DateTime.Parse(lDate, new System.Globalization.DateTimeFormatInfo(), System.Globalization.DateTimeStyles.AllowWhiteSpaces); * } * catch * { * return System.DateTime.ParseExact(lDate, "ddd, d MMM yyyy HH':'mm':'ss zzz", new System.Globalization.DateTimeFormatInfo(), System.Globalization.DateTimeStyles.AllowWhiteSpaces); * }*/ }
/// <summary> /// Parses a single header and sets member variables according to it. /// </summary> /// <param name="headerName">The name of the header</param> /// <param name="headerValue">The value of the header in unfolded state (only one line)</param> /// <exception cref="ArgumentNullException">If <paramref name="headerName"/> or <paramref name="headerValue"/> is <see langword="null"/></exception> private void ParseHeader(string headerName, string headerValue) { if (headerName == null) { throw new ArgumentNullException("headerName"); } if (headerValue == null) { throw new ArgumentNullException("headerValue"); } switch (headerName.ToUpperInvariant()) { // See http://tools.ietf.org/html/rfc5322#section-3.6.3 case "TO": To = RfcMailAddress.ParseMailAddresses(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.3 case "CC": Cc = RfcMailAddress.ParseMailAddresses(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.3 case "BCC": Bcc = RfcMailAddress.ParseMailAddresses(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.2 case "FROM": // There is only one MailAddress in the from field From = RfcMailAddress.ParseMailAddress(headerValue); break; // http://tools.ietf.org/html/rfc5322#section-3.6.2 // The implementation here might be wrong case "REPLY-TO": // This field may actually be a list of addresses, but no // such case has been encountered ReplyTo = RfcMailAddress.ParseMailAddress(headerValue); break; // http://tools.ietf.org/html/rfc5322#section-3.6.2 case "SENDER": Sender = RfcMailAddress.ParseMailAddress(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.5 // RFC 5322: // The "Keywords:" field contains a comma-separated list of one or more // words or quoted-strings. // The field are intended to have only human-readable content // with information about the message case "KEYWORDS": string[] keywordsTemp = headerValue.Split(','); foreach (string keyword in keywordsTemp) { // Remove the quotes if there is any Keywords.Add(StringUtility.RemoveQuotesIfAny(keyword.Trim())); } break; // See http://tools.ietf.org/html/rfc5322#section-3.6.7 case "RECEIVED": // Simply add the value to the list Received.Add(new Received(headerValue.Trim())); break; case "IMPORTANCE": Importance = HeaderFieldParser.ParseImportance(headerValue.Trim()); break; // See http://tools.ietf.org/html/rfc3798#section-2.1 case "DISPOSITION-NOTIFICATION-TO": DispositionNotificationTo = RfcMailAddress.ParseMailAddresses(headerValue); break; case "MIME-VERSION": MimeVersion = headerValue.Trim(); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.5 case "SUBJECT": Subject = EncodedWord.Decode(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.7 case "RETURN-PATH": // Return-paths does not include a username, but we // may still use the address parser ReturnPath = RfcMailAddress.ParseMailAddress(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.4 // Example Message-ID // <*****@*****.**> case "MESSAGE-ID": MessageId = HeaderFieldParser.ParseId(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.4 case "IN-REPLY-TO": InReplyTo = HeaderFieldParser.ParseMultipleIDs(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.4 case "REFERENCES": References = HeaderFieldParser.ParseMultipleIDs(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.1)) case "DATE": Date = headerValue.Trim(); DateSent = Rfc2822DateTime.StringToDate(headerValue); break; // See http://tools.ietf.org/html/rfc2045#section-6 // See ContentTransferEncoding class for more details case "CONTENT-TRANSFER-ENCODING": ContentTransferEncoding = HeaderFieldParser.ParseContentTransferEncoding(headerValue.Trim()); break; // See http://tools.ietf.org/html/rfc2045#section-8 case "CONTENT-DESCRIPTION": // Human description of for example a file. Can be encoded ContentDescription = EncodedWord.Decode(headerValue.Trim()); break; // See http://tools.ietf.org/html/rfc2045#section-5.1 // Example: Content-type: text/plain; charset="us-ascii" case "CONTENT-TYPE": ContentType = HeaderFieldParser.ParseContentType(headerValue); break; // See http://tools.ietf.org/html/rfc2183 case "CONTENT-DISPOSITION": ContentDisposition = HeaderFieldParser.ParseContentDisposition(headerValue); break; // See http://tools.ietf.org/html/rfc2045#section-7 // Example: <foo4*[email protected]> case "CONTENT-ID": ContentId = HeaderFieldParser.ParseId(headerValue); break; default: // This is an unknown header // Custom headers are allowed. That means headers // that are not mentionen in the RFC. // Such headers start with the letter "X" // We do not have any special parsing of such // Add it to unknown headers UnknownHeaders.Add(headerName, headerValue); break; } }
/// <summary> /// Parses a 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> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentDisposition ParseContentDisposition(string headerValue) { if (headerValue == null) { throw new ArgumentNullException(nameof(headerValue)); } // See http://www.ietf.org/rfc/rfc2183.txt for RFC definition // Create empty ContentDisposition - we will fill in details as we read them var contentDisposition = new ContentDisposition(); // Now decode the parameters var parameters = Rfc2231Decoder.Decode(headerValue); foreach (var keyValuePair in parameters) { var key = keyValuePair.Key.ToUpperInvariant().Trim(); var value = Utility.RemoveQuotesIfAny(keyValuePair.Value.Trim()); switch (key) { case "": // This is the DispisitionType - it has no key since it is the first one // and has no = in it. contentDisposition.DispositionType = value; 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. case "NAME": case "FILENAME": // The filename might be in qoutes, and it might be encoded-word encoded contentDisposition.FileName = EncodedWord.Decode(value); 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); contentDisposition.CreationDate = creationDate; break; case "MODIFICATION-DATE": case "MODIFICATION-DATE-PARM": var midificationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.ModificationDate = midificationDate; break; case "READ-DATE": var readDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.ReadDate = readDate; break; case "SIZE": contentDisposition.Size = SizeParser.Parse(value); break; case "CHARSET": // ignoring invalid parameter in Content-Disposition case "VOICE": break; default: if (!key.StartsWith("X-")) { throw new ArgumentException( "Unknown parameter in Content-Disposition. Ask developer to fix! Parameter: " + key); } contentDisposition.Parameters.Add(key, value); break; } } return(contentDisposition); }
public void TestCustomFormatTakesPriorityExample() { //If a date matches a supplied custom format, then that should be used over the default // Here a custom format specifies that a UK date format should be assumed (dd/mm/yyyy), whereas // by defualt this date would be parsed in the US date format (mm/dd/yyyy) //Note that if it was parsed in the US format it would then warn that the day was incorrect as debug message, // but for some cases even the day will be correct Rfc2822DateTime.CustomDateTimeFormats = new string[] { "ddd, dd MM yyyy HH:mm:ss" }; Assert.AreEqual(new DateTime(2015, 06, 04, 09, 08, 22, DateTimeKind.Utc), Rfc2822DateTime.StringToDate("Thu, 04 06 2015 09:08:22")); //Reset the custom formats Rfc2822DateTime.CustomDateTimeFormats = null; }
/// <summary> /// Parses a 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> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentDisposition ParseContentDisposition(string headerValue) { if (headerValue == null) { throw new ArgumentNullException("headerValue"); } // See http://www.ietf.org/rfc/rfc2183.txt for RFC definition // Create empty ContentDisposition - we will fill in details as we read them ContentDisposition contentDisposition = new ContentDisposition(); // Now decode the parameters List <KeyValuePair <string, string> > parameters = Rfc2231Decoder.Decode(headerValue); foreach (KeyValuePair <string, string> keyValuePair in parameters) { string key = keyValuePair.Key.Trim(); string value = keyValuePair.Value; switch (key) { case "": // This is the DispisitionType - it has no key since it is the first one // and has no = in it. contentDisposition.DispositionType = value; break; case "filename": // The filename might be in qoutes, and it might be encoded-word encoded contentDisposition.FileName = EncodedWord.Decode(StringHelper.RemoveQuotesIfAny(value)); 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 DateTime creationDate = new DateTime(Rfc2822DateTime.StringToDate(value.Replace("\"", "")).Ticks); contentDisposition.CreationDate = creationDate; break; case "modification-date": DateTime midificationDate = new DateTime(Rfc2822DateTime.StringToDate(value.Replace("\"", "")).Ticks); contentDisposition.ModificationDate = midificationDate; break; case "read-date": DateTime readDate = new DateTime(Rfc2822DateTime.StringToDate(value.Replace("\"", "")).Ticks); contentDisposition.ReadDate = readDate; break; case "size": contentDisposition.Size = int.Parse(value, CultureInfo.InvariantCulture); break; default: throw new ArgumentException("Unknown parameter in Content-Disposition. Ask developer to fix!"); } } return(contentDisposition); }