/// <summary> /// Generates a new Content-ID for the part. /// </summary> public void SetContentId() { this.ContentId = "AMLv2" + Codec.GetUniqueString() + "@" + System.Net.Dns.GetHostName(); }
/// <summary> /// Parses the header. /// </summary> /// <param name="header">The header.</param> public static void ParseHeader(ref Header header) { #if !PocketPC string hdr = Encoding.GetEncoding("iso-8859-1").GetString(header.OriginalData, 0, header.OriginalData.Length); #else string hdr = Pop3Client.PPCEncode.GetString(header.OriginalData, 0, header.OriginalData.Length); #endif hdr = Regex.Match(hdr, @"[\s\S]+?((?=\r?\n\r?\n)|\Z)").Value; hdr = Unfold(hdr); //hdr = hdr); Match m = Regex.Match(hdr, @"(?<=((\r?\n)|\n)|\A)\S+:(.|(\r?\n[\t ]))+(?=((\r?\n)\S)|\Z)"); while (m.Success) { string name = FormatFieldName(m.Value.Substring(0, m.Value.IndexOf(':'))); string value = Codec.RFC2047Decode(m.Value.Substring(m.Value.IndexOf(":") + 1)).Trim('\r', '\n').TrimStart(' '); if (name.Equals("received")) { header.Trace.Add(ParseTrace(m.Value.Trim(' '))); } else if (name.Equals("to")) { header.To = ParseAddresses(value); } else if (name.Equals("cc")) { header.Cc = ParseAddresses(value); } else if (name.Equals("bcc")) { header.Bcc = ParseAddresses(value); } else if (name.Equals("reply-to")) { header.ReplyTo = ParseAddress(value); } else if (name.Equals("from")) { header.From = ParseAddress(value); } else if (name.Equals("sender")) { header.Sender = ParseAddress(value); } else if (name.Equals("content-type")) { header.ContentType = GetContentType(m.Value); } else if (name.Equals("content-disposition")) { header.ContentDisposition = GetContentDisposition(m.Value); } //else //{ header.HeaderFields.Add(name, value); header.HeaderFieldNames.Add(name, m.Value.Substring(0, m.Value.IndexOf(':'))); //} m = m.NextMatch(); if (HeaderFieldParsing != null) { HeaderFieldParsing(null, header); } } }
/// <summary> /// Decodes the given string from the format specified in RFC 2047 (=?charset?value?=). /// </summary> /// <param name="input">The string to be decoded.</param> /// <returns>The decoded string.</returns> /// <example> /// The example below illustrates the decoding of a string. /// <code> /// C# /// /// string input = "I once wrote that =?iso-8859-1?B?QWN0aXZlTWFpbCByb2NrcyAhIEhlcmUgYXJlIHNvbWUgd2VpcmQgY2hhcmFjdGVycyA95y4=?="; /// string output = Codec.RFC2047Decode(input); /// </code> /// /// output returns I once wrote that ActiveMail rocks ! Here are some weird characters =ç. /// </example> public static string RFC2047Decode(string input) { // Remove whitespaces string text = whiteSpace.Replace( input, delegate(Match a) { return("?==?"); }); //SUPPORT_CODE_BEGIN //Todo: Code below added for automated charset detection //This code not part of RFC 2084 var m = encodedWord.Match(text); if (m.Success) { //SUPPORT_CODE_END text = DecodeSameEncodedParts(text); // Decode encoded words text = encodedWord.Replace( text, delegate(Match curRes) { if (curRes.Groups["encoding"].Value.Equals("B", StringComparison.OrdinalIgnoreCase)) { var message = curRes.Groups["message"].Value.Replace(" ", ""); var encoder = GetEncoding(curRes.Groups["charset"].Value); try { return(encoder.GetString(Convert.FromBase64String(message))); } catch { int index = message.LastIndexOf("="); while (index != -1) { // remove the extra character message = message.Remove(index); try { return(encoder.GetString(Convert.FromBase64String(message))); } catch { index = message.LastIndexOf("="); } } throw; } } else { string tmpbuffer = curRes.Groups["message"].Value.Replace("_", " "); return(Codec.FromQuotedPrintable(tmpbuffer, curRes.Groups["charset"].Value)); } }); //SUPPORT_CODE_BEGIN } else { var encoder = GetEncoding(""); byte[] text_in_bytes = encoder.GetBytes(text); var charset_detector = new CharsetDetector(); charset_detector.Feed(text_in_bytes, 0, text_in_bytes.Length); charset_detector.DataEnd(); if (charset_detector.Charset != null) { text = GetEncoding(charset_detector.Charset).GetString(text_in_bytes); } } //SUPPORT_CODE_END return(text); }
private static void ParseHeaderFields(MimePart part, int headerEnd) { string header = Unfold(part.OriginalContent.Substring(0, headerEnd)); Match m = Regex.Match(header, @"(?<=((\r?\n)|\n)|\A)\S+:(.|(\r?\n[\t ]))+(?=((\r?\n)\S)|\Z)"); while (m.Success) { if (m.Value.ToLower().StartsWith("content-type:")) { part.ContentType = GetContentType(m.Value); } else if (m.Value.ToLower().StartsWith("content-disposition:")) { part.ContentDisposition = GetContentDisposition(m.Value); } part.HeaderFields.Add(FormatFieldName(m.Value.Substring(0, m.Value.IndexOf(':'))), Codec.RFC2047Decode(m.Value.Substring(m.Value.IndexOf(':') + 1).Trim(' ', '\r', '\n'))); part.HeaderFieldNames.Add(FormatFieldName(m.Value.Substring(0, m.Value.IndexOf(':'))), Codec.RFC2047Decode(m.Value.Substring(0, m.Value.IndexOf(':')).Trim(' ', '\r', '\n'))); m = m.NextMatch(); } }
private void AppendContentEncoding(StringBuilder builder, bool forceBase64Encoding) { var headerValue = forceBase64Encoding ? "base64" : HeaderFields["content-transfer-encoding"]; builder.AppendFormat("{0}: {1}\r\n", Codec.GetFieldName("content-transfer-encoding"), headerValue); }
/// <summary> /// The MIME representation of the header. /// </summary> /// <param name="removeBlindCopies">if set to <c>true</c> remove blind copies (BCC).</param> /// <returns></returns> public string ToHeaderString(bool removeBlindCopies) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); /*foreach (TraceInfo trace in this.Trace) sb.AppendLine("Received: " + trace.ToString()); * if (!this.From.Email.Equals(string.Empty)) sb.AppendLine("From: " + this.From.Merged); * if (!this.Sender.Email.Equals(string.Empty)) sb.AppendLine("Sender: " + this.Sender.Merged); * if (this.To.Count > 0) sb.AppendLine("To: " + this.To.Merged); * if (this.Cc.Count > 0) sb.AppendLine("Cc: " + this.Cc.Merged); * if (this.Bcc.Count > 0) sb.AppendLine("Bcc: " + this.Bcc.Merged); * if (!this.ReplyTo.Email.Equals(string.Empty)) sb.AppendLine("Reply-to: " + this.ReplyTo.Merged);*/ foreach (TraceInfo trace in this.Trace) { this.AddHeaderField("Received", trace.ToString()); } if (!this.From.Email.Equals(string.Empty)) { this.AddHeaderField("From", this.From.Merged); } if (!this.Sender.Email.Equals(string.Empty)) { this.AddHeaderField("Sender", this.Sender.Merged); } if (this.To.Count > 0) { this.AddHeaderField("To", this.To.Merged); } if (this.Cc.Count > 0) { this.AddHeaderField("Cc", this.Cc.Merged); } if (this.Bcc.Count > 0 && !removeBlindCopies) { this.AddHeaderField("Bcc", this.Bcc.Merged); } if (!this.ReplyTo.Email.Equals(string.Empty)) { this.AddHeaderField("Reply-To", this.ReplyTo.Merged); } if (this.Date.Equals(DateTime.MinValue)) { this.Date = DateTime.Now; } if (this.MessageId == null || this.MessageId == string.Empty) { this.MessageId = "<AU" + Codec.GetUniqueString() + "@" + System.Net.Dns.GetHostName() + ">"; } if (this.ContentType.MimeType.Length > 0) { string contentType = this.ContentType.ToString(); contentType = contentType.Substring(contentType.IndexOf(":") + 1).TrimStart(' '); this.AddHeaderField("Content-Type", contentType); } if (this.ContentDisposition.Disposition.Length > 0) { string contentDisposition = this.ContentDisposition.ToString(); contentDisposition = contentDisposition.Substring(contentDisposition.IndexOf(":") + 1).TrimStart(' '); this.AddHeaderField("Content-Disposition", contentDisposition); } if (this.ContentType.Type.Equals("text")) { string contentTransferEncoding = this.ContentTransferEncoding.ToString(); contentTransferEncoding = contentTransferEncoding.Substring(contentTransferEncoding.IndexOf(":") + 1).TrimStart(' '); this.AddHeaderField("Content-Transfer-Encoding", "quoted-printable"); } //sb.Append(this.ContentType.ToString() + "\r\n"); //if (this.ContentDisposition.Disposition == "attachment") sb.AppendLine(this.ContentDisposition.ToString()); System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); System.Version v = asm.GetName().Version; this.AddHeaderField("X-Mailer", "ActiveUp.MailSystem " + v.Major + "." + v.Minor + "." + v.Build + " www.activeup.com"); foreach (string key in this.HeaderFields.AllKeys) { for (int i = 0; i < this.HeaderFields.GetValues(key).Length; i++) { sb.Append(this.HeaderFieldNames.GetValues(key)[i] + ": " + this.HeaderFields.GetValues(key)[i] + "\r\n"); } } /*string header = sb.ToString().TrimEnd('\r', '\n'); * string foldedHeader = string.Empty; * * StringReader sr = new StringReader(header); * while(sr.Peek() != -1) * { * foldedHeader += Parser.Fold(sr.ReadLine()) + "\r\n"; * }*/ return(sb.ToString().TrimEnd('\r', '\n')); }
/// <summary> /// Parses the MIME part. /// </summary> /// <param name="data">The data.</param> /// <returns></returns> public static MimePart ParseMimePart(string data, Message message) { MimePart part = new MimePart(); part.ParentMessage = message; part.OriginalContent = data; try { // Separate header and body. int headerEnd = Regex.Match(data, @".(?=\r?\n\r?\n)").Index + 1; int bodyStart = Regex.Match(data, @"(?<=\r?\n\r?\n).").Index; //TODO: remove this workaround if (bodyStart == 0) { //bodyStart = data.IndexOf("\r\n\r\n"); // Fix for a bug - the bodyStart was -1 (Invalid), MCALADO: 04/07/2008 int indexBody = data.IndexOf("\r\n\r\n"); if (indexBody > 0) { bodyStart = indexBody; } } if (data.Length >= headerEnd) { string header = data.Substring(0, headerEnd); header = Parser.Unfold(header); //header = header); // The bodyStart need to be greather than data.length - MCALADO: 04/07/2008 string body = string.Empty; if (bodyStart < data.Length) { body = data.Substring(bodyStart); } // Store the (maybe still encoded) body. part.TextContent = body; // Parse header fields and their parameters. Match m = Regex.Match(header, @"(?<=((\r?\n)|\n)|\A)\S+:(.|(\r?\n[\t ]))+(?=((\r?\n)\S)|\Z)"); while (m.Success) { if (m.Value.ToLower().StartsWith("content-type:")) { part.ContentType = Parser.GetContentType(m.Value); } else if (m.Value.ToLower().StartsWith("content-disposition:")) { part.ContentDisposition = Parser.GetContentDisposition(m.Value); } part.HeaderFields.Add(FormatFieldName(m.Value.Substring(0, m.Value.IndexOf(':'))), Codec.RFC2047Decode(m.Value.Substring(m.Value.IndexOf(':') + 1).Trim(' ', '\r', '\n'))); part.HeaderFieldNames.Add(FormatFieldName(m.Value.Substring(0, m.Value.IndexOf(':'))), Codec.RFC2047Decode(m.Value.Substring(0, m.Value.IndexOf(':')).Trim(' ', '\r', '\n'))); m = m.NextMatch(); } // Build the part tree. // This is a container part. if (part.ContentType.Type.ToLower().Equals("multipart")) { Parser.ParseSubParts(ref part, message); } // This is a nested message. else if (part.ContentType.Type.ToLower().Equals("message")) { // TODO } // This is a leaf of the part tree // Check necessary for single part emails (fix from alex294 on CodePlex) // Why would we consider the body only to the first string? Doesn't make sense - and fails //else if (part.ContentType.Type.ToLower().Equals("text")) //{ // int BodyEnd = body.IndexOf(' '); // if (BodyEnd > 0) // { // part.TextContent = body.Substring(0, BodyEnd); // } //} DecodePartBody(ref part); try { BodyParsed(null, message); } catch (Exception) { // event is not supported. } } } catch (Exception ex) { throw new ParsingException(ex.Message); } return(part); }
/// <summary> /// The MIME representation of the header. /// </summary> /// <param name="removeBlindCopies">if set to <c>true</c> remove blind copies (BCC).</param> /// <param name="forceBase64Encoding">if set to <c>true</c> forces inner elements to be base64 encoded</param> /// <returns></returns> public string ToHeaderString(bool removeBlindCopies, bool forceBase64Encoding = false) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); /*foreach (TraceInfo trace in this.Trace) sb.AppendLine("Received: " + trace.ToString()); * if (!this.From.Email.Equals(string.Empty)) sb.AppendLine("From: " + this.From.Merged); * if (!this.Sender.Email.Equals(string.Empty)) sb.AppendLine("Sender: " + this.Sender.Merged); * if (this.To.Count > 0) sb.AppendLine("To: " + this.To.Merged); * if (this.Cc.Count > 0) sb.AppendLine("Cc: " + this.Cc.Merged); * if (this.Bcc.Count > 0) sb.AppendLine("Bcc: " + this.Bcc.Merged); * if (!this.ReplyTo.Email.Equals(string.Empty)) sb.AppendLine("Reply-to: " + this.ReplyTo.Merged);*/ foreach (TraceInfo trace in Trace) { AddHeaderField("Received", trace.ToString()); } if (!From.Email.Equals(string.Empty)) { AddHeaderField("From", From.Merged); } if (!Sender.Email.Equals(string.Empty)) { AddHeaderField("Sender", Sender.Merged); } if (To.Count > 0) { AddHeaderField("To", To.Merged); } if (Cc.Count > 0) { AddHeaderField("Cc", Cc.Merged); } if (Bcc.Count > 0 && !removeBlindCopies) { AddHeaderField("Bcc", Bcc.Merged); } if (!ReplyTo.Email.Equals(string.Empty)) { AddHeaderField("Reply-To", ReplyTo.Merged); } if (Date.Equals(DateTime.MinValue)) { Date = DateTime.Now; } if (string.IsNullOrEmpty(MessageId)) { MessageId = "<AU" + Codec.GetUniqueString() + "@" + System.Net.Dns.GetHostName() + ">"; } if (ContentType.MimeType.Length > 0) { string contentType = ContentType.ToString(); contentType = contentType.Substring(contentType.IndexOf(":") + 1).TrimStart(' '); AddHeaderField("Content-Type", contentType); } if (ContentDisposition.Disposition.Length > 0) { string contentDisposition = ContentDisposition.ToString(); contentDisposition = contentDisposition.Substring(contentDisposition.IndexOf(":") + 1).TrimStart(' '); AddHeaderField("Content-Disposition", contentDisposition); } if (forceBase64Encoding) { AddHeaderField("Content-Transfer-Encoding", "base64"); } else if (ContentType.Type.Equals("text")) { AddHeaderField("Content-Transfer-Encoding", "quoted-printable"); } System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); Version v = asm.GetName().Version; AddHeaderField("X-Mailer", "ActiveUp.MailSystem " + v.Major + "." + v.Minor + "." + v.Build + " www.activeup.com"); foreach (string key in HeaderFields.AllKeys) { for (int i = 0; i < HeaderFields.GetValues(key).Length; i++) { sb.Append(HeaderFieldNames.GetValues(key)[i] + ": " + HeaderFields.GetValues(key)[i] + "\r\n"); } } return(sb.ToString().TrimEnd('\r', '\n')); }