using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.Specialized; using System.IO; namespace sharpknife.Utils { public class MimePart { public NameValueCollection headers = new NameValueCollection(); public string body; } public class MailUtils { public static Queue SplitLines(string message) { Queue lines = new Queue(); using (StringReader reader = new StringReader(message)) { string line = string.Empty; while ((line = reader.ReadLine()) != null) { lines.Enqueue(line); } } return lines; } public static NameValueCollection ParseHeaders(Queue lines) { NameValueCollection headers = new NameValueCollection(); string lastHeader = string.Empty; string line = string.Empty; // Header stops when an empty line is found while (lines.Count > 0 && !string.IsNullOrEmpty(lines.Peek())) { line = lines.Dequeue(); // Lines starting with white space or tab are part of the previous line if (line.StartsWith(" ") || line.StartsWith(Convert.ToString('\t'))) { headers[lastHeader] = string.Concat(headers[lastHeader], line); continue; } int separatorIndex = line.IndexOf(':'); if (separatorIndex < 0) { System.Diagnostics.Debug.WriteLine("Invalid header:{0}", line); continue; } string headerName = line.Substring(0, separatorIndex); string headerValue = line.Substring(separatorIndex + 1).Trim(new char[] { ' ', '\t' }); headers.Add(headerName.ToLower(), headerValue); lastHeader = headerName; } if (lines.Count > 0) { lines.Dequeue(); } return headers; } public static List ParseBody(Queue lines, string boundary) { List parts = new List(); if (!string.IsNullOrEmpty(boundary)) { MimePart part = null; while (lines.Count > 0) { if (string.Equals(lines.Peek(), string.Format("--{0}", boundary))) { part = new MimePart(); parts.Add(part); } part.headers = ParseHeaders(lines); string line = string.Empty; while (lines.Count > 0) { line = lines.Peek(); if (line == string.Format("--{0}", boundary)) break; line = lines.Dequeue(); part.body += line + Environment.NewLine; } /*Check to verify the current line is not the same as the parent starting boundary. If it is the same as the parent starting boundary this indicates existence of a new child entity. Return and process the next child.*/ //if (_entity.Parent != null // && string.Equals(_entity.Parent.StartBoundary, lines.Peek())) //{ // return; //} //if (string.Equals(lines.Peek(), _entity.StartBoundary)) //{ // AddChildEntity(_entity, lines); //} //Parse a new child mime part. //else if (string.Equals(_entity.ContentType.MediaType, // MediaTypes.MessageRfc822, StringComparison.InvariantCultureIgnoreCase) // && string.Equals(_entity.ContentDisposition.DispositionType, // DispositionTypeNames.Attachment, // StringComparison.InvariantCultureIgnoreCase)) //{ // /*If the content type is message/rfc822 the // stop condition to parse headers has already been encountered. // But, a content type of message/rfc822 would // have the message headers immediately following the mime // headers so we need to parse the headers for the attached message.*/ // AddChildEntity(_entity, lines); // break; //} //else //{ // _entity.EncodedMessage.Append // (string.Concat(lines.Dequeue(), Pop3Commands.Crlf)); //} //Append the message content. } } //Parse a multipart message. else { MimePart part = new MimePart(); parts.Add(part); while (lines.Count > 0) { while (lines.Count > 0) { string line = lines.Dequeue(); part.body += line + Environment.NewLine; } } } //Parse a single part message. return parts; } } }