/// <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) { if (headerValue == null) { throw new ArgumentNullException("headerValue"); } // Remember the raw input if someone whishes to use it Raw = 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(";") + 1); Date = Rfc2822DateTime.StringToDate(datePart); } Names = ParseDictionary(headerValue); }
/// <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.ToUpperInvariant().Trim(); string value = keyValuePair.Value.Trim().RemoveQuotesIfAny(); 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 DateTime creationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.CreationDate = creationDate; break; case "MODIFICATION-DATE": DateTime midificationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.ModificationDate = midificationDate; break; case "READ-DATE": DateTime 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 break; default: if (key.StartsWith("X-")) { contentDisposition.Parameters.Add(key, value); break; } throw new ArgumentException( "Unknown parameter in Content-Disposition. Ask developer to fix! Parameter: " + key); } } return(contentDisposition); }
/// <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(keyword.Trim().RemoveQuotesIfAny()); } 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; } }