protected override void VisitMultipartRelated(MultipartRelated related) { var root = related.Root; _stack.Add(related); root.Accept(this); _stack.RemoveAt(_stack.Count - 1); }
void Render (MultipartRelated related) { var client = new MultipartRelatedWebViewClient (related); webView.SetWebViewClient (client); Render (related.Root); }
protected override void VisitMultipartRelated (MultipartRelated related) { var root = related.Root; // push this multipart/related onto our stack stack.Add (related); // visit the root document root.Accept (this); // pop this multipart/related off our stack stack.RemoveAt (stack.Count - 1); }
void RenderMultipartRelated (MultipartRelated related) { var root = related.Root; if (root == null) return; var client = new MultipartRelatedWebViewClient (related); webView.SetWebViewClient (client); Render (root); }
public void TestArgumentExceptions () { var related = new MultipartRelated (); string mimeType, charset; Assert.Throws<ArgumentNullException> (() => new MultipartRelated ((MimeEntityConstructorArgs) null)); Assert.Throws<ArgumentNullException> (() => related.Open (null, out mimeType, out charset)); Assert.Throws<ArgumentNullException> (() => related.Open (null)); Assert.Throws<ArgumentNullException> (() => related.Contains ((Uri) null)); Assert.Throws<ArgumentNullException> (() => related.IndexOf ((Uri) null)); Assert.Throws<ArgumentNullException> (() => related.Accept (null)); Assert.Throws<ArgumentNullException> (() => related.Root = null); Assert.Throws<FileNotFoundException> (() => related.Open (new Uri ("http://www.xamarin.com/logo.png"), out mimeType, out charset)); Assert.Throws<FileNotFoundException> (() => related.Open (new Uri ("http://www.xamarin.com/logo.png"))); }
public void TestDocumentRoot () { var gif = new MimePart ("image", "gif") { ContentDisposition = new ContentDisposition (ContentDisposition.Inline) { FileName = "empty.gif" }, ContentId = MimeUtils.GenerateMessageId () }; var jpg = new MimePart ("image", "jpg") { ContentDisposition = new ContentDisposition (ContentDisposition.Inline) { FileName = "empty.jpg" }, ContentId = MimeUtils.GenerateMessageId () }; var html = new TextPart ("html") { Text = "This is the html body...", ContentId = MimeUtils.GenerateMessageId () }; var related = new MultipartRelated (gif, jpg, html); string start; related.ContentType.Parameters["type"] = "text/html"; related.ContentType.Parameters["start"] = "<" + html.ContentId + ">"; Assert.AreEqual (3, related.Count, "Initial Count"); Assert.AreEqual (html, related.Root, "Initial Root"); Assert.AreEqual (html, related[2], "Initial Root should be the 3rd item."); var root = new TextPart ("html") { Text = "This is the replacement root document..." }; related.Root = root; Assert.AreEqual (3, related.Count, "Count"); Assert.AreEqual (root, related.Root, "Root"); Assert.AreEqual (root, related[2], "Root should be the 3rd item."); Assert.IsNotNullOrEmpty (root.ContentId, "Root's Content-Id should not be null."); start = "<" + root.ContentId + ">"; Assert.AreEqual (start, related.ContentType.Parameters["start"], "The start parameter does not match."); related.Clear (); related.Add (gif); related.Add (jpg); related.Root = html; Assert.AreEqual (3, related.Count, "Count"); Assert.AreEqual (html, related.Root, "Root"); Assert.AreEqual (html, related[0], "Root should be the 1st item."); // Note: MimeKit no longer sets the "start" parameter if the root is the first MIME part due to a bug in Thunderbird. Assert.IsNull (related.ContentType.Parameters["start"], "The start parameter should be null."); }
void Render (MultipartRelated related) { var cache = new MultipartRelatedUrlCache (related); NSUrlCache.SharedCache = cache; Render (related.Root); }
/// <summary> /// Visit the multipart/related MIME entity. /// </summary> /// <remarks> /// Visits the multipart/related MIME entity. /// </remarks> /// <example> /// <code language="c#" source="Examples\MimeVisitorExamples.cs" region="HtmlPreviewVisitor" /> /// </example> /// <param name="related">The multipart/related MIME entity.</param> protected internal virtual void VisitMultipartRelated (MultipartRelated related) { VisitMultipart (related); }
/// <summary> /// Constructs the message body based on the text-based bodies, the linked resources, and the attachments. /// </summary> /// <remarks> /// Combines the <see cref="Attachments"/>, <see cref="LinkedResources"/>, <see cref="TextBody"/>, /// and <see cref="HtmlBody"/> into the proper MIME structure suitable for display in many common /// mail clients. /// </remarks> /// <returns>The message body.</returns> public MimeEntity ToMessageBody () { Multipart alternative = null; MimeEntity body = null; if (!string.IsNullOrEmpty (TextBody)) { var text = new TextPart ("plain"); text.Text = TextBody; if (!string.IsNullOrEmpty (HtmlBody)) { alternative = new Multipart ("alternative"); alternative.Add (text); body = alternative; } else { body = text; } } if (!string.IsNullOrEmpty (HtmlBody)) { var text = new TextPart ("html"); MimeEntity html; text.ContentId = MimeUtils.GenerateMessageId (); text.Text = HtmlBody; if (LinkedResources.Count > 0) { var related = new MultipartRelated { Root = text }; foreach (var resource in LinkedResources) related.Add (resource); html = related; } else { html = text; } if (alternative != null) alternative.Add (html); else body = html; } if (Attachments.Count > 0) { var mixed = new Multipart ("mixed"); if (body != null) mixed.Add (body); foreach (var attachment in Attachments) mixed.Add (attachment); body = mixed; } return body ?? new TextPart ("plain") { Text = string.Empty }; }
void RenderMultipartRelated (MultipartRelated related) { var root = related.Root; if (root == null) return; var cache = new MultipartRelatedUrlCache (related); NSUrlCache.SharedCache = cache; Render (root); }
void RenderMultipartRelated (MultipartRelated related) { var root = related.Root; var multipart = root as Multipart; var text = root as TextPart; if (multipart != null) { // Note: the root document can sometimes be a multipart/alternative. // A multipart/alternative is just a collection of alternate views. // The last part is the format that most closely matches what the // user saw in his or her email client's WYSIWYG editor. for (int i = multipart.Count; i > 0; i--) { var body = multipart[i - 1] as TextPart; if (body == null) continue; // our preferred mime-type is text/html if (body.ContentType.Matches ("text", "html")) { text = body; break; } if (text == null) text = body; } } // check if we have a text/html document if (text != null) { if (text.ContentType.Matches ("text", "html")) { // replace image src urls that refer to related MIME parts with "data:" urls // Note: we could also save the related MIME part content to disk and use // file:// urls instead. var ctx = new MultipartRelatedImageContext (related); var converter = new HtmlToHtml () { HtmlTagCallback = ctx.HtmlTagCallback }; var html = converter.Convert (text.Text); webBrowser.DocumentText = html; } else { RenderText (text); } } else if (root != null) { // we don't know what we have, so render it as an entity Render (root); } }
public MultipartRelatedWebViewClient (MultipartRelated related) { this.related = related; }
public MultipartRelatedUrlCache (MultipartRelated related) { this.related = related; }
/// <summary> /// Creates a new <see cref="MimeMessage"/> from a <see cref="System.Net.Mail.MailMessage"/>. /// </summary> /// <remarks> /// Creates a new <see cref="MimeMessage"/> from a <see cref="System.Net.Mail.MailMessage"/>. /// </remarks> /// <returns>The equivalent <see cref="MimeMessage"/>.</returns> /// <param name="message">The message.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="message"/> is <c>null</c>. /// </exception> public static MimeMessage CreateFromMailMessage (MailMessage message) { if (message == null) throw new ArgumentNullException ("message"); var headers = new List<Header> (); foreach (var field in message.Headers.AllKeys) { foreach (var value in message.Headers.GetValues (field)) headers.Add (new Header (field, value)); } var msg = new MimeMessage (ParserOptions.Default, headers); MimeEntity body = null; // Note: If the user has already sent their MailMessage via System.Net.Mail.SmtpClient, // then the following MailMessage properties will have been merged into the Headers, so // check to make sure our MimeMessage properties are empty before adding them. if (msg.Sender == null && message.Sender != null) msg.Sender = (MailboxAddress) message.Sender; if (msg.From.Count == 0 && message.From != null) msg.From.Add ((MailboxAddress) message.From); #if NET_3_5 if (msg.ReplyTo.Count == 0 && message.ReplyTo != null) msg.ReplyTo.Add ((MailboxAddress) message.ReplyTo); #else if (msg.ReplyTo.Count == 0 && message.ReplyToList.Count > 0) msg.ReplyTo.AddRange ((InternetAddressList) message.ReplyToList); #endif if (msg.To.Count == 0 && message.To.Count > 0) msg.To.AddRange ((InternetAddressList) message.To); if (msg.Cc.Count == 0 && message.CC.Count > 0) msg.Cc.AddRange ((InternetAddressList) message.CC); if (msg.Bcc.Count == 0 && message.Bcc.Count > 0) msg.Bcc.AddRange ((InternetAddressList) message.Bcc); if (string.IsNullOrEmpty (msg.Subject)) msg.Subject = message.Subject ?? string.Empty; switch (message.Priority) { case MailPriority.Normal: msg.Headers.RemoveAll (HeaderId.XMSMailPriority); msg.Headers.RemoveAll (HeaderId.Importance); msg.Headers.RemoveAll (HeaderId.XPriority); msg.Headers.RemoveAll (HeaderId.Priority); break; case MailPriority.High: msg.Headers.Replace (HeaderId.Priority, "urgent"); msg.Headers.Replace (HeaderId.Importance, "high"); msg.Headers.Replace (HeaderId.XPriority, "2 (High)"); break; case MailPriority.Low: msg.Headers.Replace (HeaderId.Priority, "non-urgent"); msg.Headers.Replace (HeaderId.Importance, "low"); msg.Headers.Replace (HeaderId.XPriority, "4 (Low)"); break; } if (!string.IsNullOrEmpty (message.Body)) { var text = new TextPart (message.IsBodyHtml ? "html" : "plain"); text.SetText (message.BodyEncoding ?? Encoding.UTF8, message.Body); body = text; } if (message.AlternateViews.Count > 0) { var alternative = new MultipartAlternative (); if (body != null) alternative.Add (body); foreach (var view in message.AlternateViews) { var part = GetMimePart (view); if (view.BaseUri != null) part.ContentLocation = view.BaseUri; if (view.LinkedResources.Count > 0) { var type = part.ContentType.MediaType + "/" + part.ContentType.MediaSubtype; var related = new MultipartRelated (); related.ContentType.Parameters.Add ("type", type); if (view.BaseUri != null) related.ContentLocation = view.BaseUri; related.Add (part); foreach (var resource in view.LinkedResources) { part = GetMimePart (resource); if (resource.ContentLink != null) part.ContentLocation = resource.ContentLink; related.Add (part); } alternative.Add (related); } else { alternative.Add (part); } } body = alternative; } if (body == null) body = new TextPart (message.IsBodyHtml ? "html" : "plain"); if (message.Attachments.Count > 0) { var mixed = new Multipart ("mixed"); if (body != null) mixed.Add (body); foreach (var attachment in message.Attachments) mixed.Add (GetMimePart (attachment)); body = mixed; } msg.Body = body; return msg; }
/// <summary> /// Constructs the message body based on the text-based bodies, the linked resources, and the attachments. /// </summary> /// <remarks> /// Combines the <see cref="Attachments"/>, <see cref="LinkedResources"/>, <see cref="TextBody"/>, /// and <see cref="HtmlBody"/> into the proper MIME structure suitable for display in many common /// mail clients. /// </remarks> /// <returns>The message body.</returns> public MimeEntity ToMessageBody() { MultipartAlternative alternative = null; MimeEntity body = null; if (!string.IsNullOrEmpty(TextBody)) { var text = new TextPart("plain"); text.Text = TextBody; if (!string.IsNullOrEmpty(HtmlBody)) { alternative = new MultipartAlternative(); alternative.Add(text); body = alternative; } else { body = text; } } if (!string.IsNullOrEmpty(HtmlBody)) { var text = new TextPart("html"); MimeEntity html; text.ContentId = MimeUtils.GenerateMessageId(); text.Text = HtmlBody; if (LinkedResources.Count > 0) { var related = new MultipartRelated { Root = text }; foreach (var resource in LinkedResources) { related.Add(resource); } html = related; } else { html = text; } if (alternative != null) { alternative.Add(html); } else { body = html; } } if (Attachments.Count > 0) { var mixed = new Multipart("mixed"); if (body != null) { mixed.Add(body); } foreach (var attachment in Attachments) { mixed.Add(attachment); } body = mixed; } return(body ?? new TextPart("plain") { Text = string.Empty }); }
public MultipartRelatedImageContext (MultipartRelated related) { this.related = related; }
protected override void VisitMultipartRelated (MultipartRelated related) { var multipart = new MultipartRelated (); var root = related.Root; Push (multipart); root.Accept (this); for (int i = 0; i < related.Count; i++) { if (related[i] != root) related[i].Accept (this); } Pop (); }
/// <summary> /// Visit the multipart/related MIME entity. /// </summary> /// <remarks> /// Visits the multipart/related MIME entity. /// </remarks> /// <example> /// <code language="c#" source="Examples\MimeVisitorExamples.cs" region="HtmlPreviewVisitor" /> /// </example> /// <param name="related">The multipart/related MIME entity.</param> protected internal virtual void VisitMultipartRelated(MultipartRelated related) { VisitMultipart(related); }
void Render (MultipartRelated related) { var root = related.Root; var multipart = root as Multipart; var text = root as TextPart; if (multipart != null) { // Note: the root document can sometimes be a multipart/alternative. // A multipart/alternative is just a collection of alternate views. // The last part is the format that most closely matches what the // user saw in his or her email client's WYSIWYG editor. for (int i = multipart.Count; i > 0; i--) { var body = multipart[i - 1] as TextPart; if (body == null) continue; // our preferred mime-type is text/html if (body.ContentType.Matches ("text", "html")) { text = body; break; } if (text == null) text = body; } } if (text != null && text.ContentType.Matches ("text", "html")) { var doc = new HtmlAgilityPack.HtmlDocument (); var saved = new Dictionary<MimePart, string> (); TextPart html; doc.LoadHtml (text.Text); // find references to related MIME parts and replace them with links to links to the saved attachments foreach (var img in doc.DocumentNode.SelectNodes ("//img[@src]")) { var src = img.Attributes["src"]; int index; Uri uri; if (src == null || src.Value == null) continue; // parse the <img src=...> attribute value into a Uri if (Uri.IsWellFormedUriString (src.Value, UriKind.Absolute)) uri = new Uri (src.Value, UriKind.Absolute); else uri = new Uri (src.Value, UriKind.Relative); // locate the index of the attachment within the multipart/related (if it exists) if ((index = related.IndexOf (uri)) != -1) { var attachment = related[index] as MimePart; // make sure the referenced part is a MimePart (as opposed to another Multipart or MessagePart) if (attachment != null) { string fileName; // save the attachment (if we haven't already saved it) if (!saved.TryGetValue (attachment, out fileName)) { fileName = attachment.FileName; if (string.IsNullOrEmpty (fileName)) fileName = Guid.NewGuid ().ToString (); using (var stream = File.Create (fileName)) attachment.ContentObject.DecodeTo (stream); saved.Add (attachment, fileName); } // replace the <img src=...> value with the local file name src.Value = "file://" + Path.GetFullPath (fileName); } } } if (saved.Count > 0) { // we had to make some modifications to the original html part, so create a new // (temporary) text/html part to render html = new TextPart ("html"); using (var writer = new StringWriter ()) { doc.Save (writer); html.Text = writer.GetStringBuilder ().ToString (); } } else { html = text; } Render (html); } else { Render (related.Root); } }