From a4bcf3e9ba88e60e6ccc80c21e5d213c25c348c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Wed, 7 Feb 2024 10:13:51 -0500 Subject: [PATCH] Do the same thing for AttachmentCollection.AddAsync() Also added unit tests. --- MimeKit/AttachmentCollection.cs | 36 +++++++++++++------ UnitTests/AttachmentCollectionTests.cs | 48 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/MimeKit/AttachmentCollection.cs b/MimeKit/AttachmentCollection.cs index 22400f9a8d..b4e1882dce 100644 --- a/MimeKit/AttachmentCollection.cs +++ b/MimeKit/AttachmentCollection.cs @@ -289,19 +289,33 @@ MimeEntity CreateAttachment (ContentType contentType, bool autoDetected, string return attachment; } - async Task CreateAttachmentAsync (ContentType contentType, string path, Stream stream, bool copyStream, CancellationToken cancellationToken) + async Task CreateAttachmentAsync (ContentType contentType, bool autoDetected, string path, Stream stream, bool copyStream, CancellationToken cancellationToken) { var fileName = GetFileName (path); - MimeEntity attachment; + MimeEntity attachment = null; if (contentType.IsMimeType ("message", "rfc822")) { - var message = await MimeMessage.LoadAsync (stream, cancellationToken).ConfigureAwait (false); + long position = stream.CanSeek ? stream.Position : 0; - if (!copyStream) - stream.Dispose (); + try { + var message = await MimeMessage.LoadAsync (stream, cancellationToken).ConfigureAwait (false); + + if (!copyStream) + stream.Dispose (); - attachment = new MessagePart { Message = message }; - } else { + attachment = new MessagePart { Message = message }; + } catch (FormatException) { + if (autoDetected && stream.CanSeek) { + // If the contentType was auto-detected and the stream is seekable, fall back to attaching this content as a generic stream + contentType = new ContentType ("application", "octet-stream"); + stream.Position = position; + } else { + throw; + } + } + } + + if (attachment is null) { MimePart part; if (contentType.IsMimeType ("text", "*")) { @@ -466,7 +480,7 @@ public async Task AddAsync (string fileName, Stream stream, ContentT if (contentType is null) throw new ArgumentNullException (nameof (contentType)); - var attachment = await CreateAttachmentAsync (contentType, fileName, stream, true, cancellationToken).ConfigureAwait (false); + var attachment = await CreateAttachmentAsync (contentType, false, fileName, stream, true, cancellationToken).ConfigureAwait (false); attachments.Add (attachment); @@ -589,7 +603,7 @@ public async Task AddAsync (string fileName, Stream stream, Cancella if (stream is null) throw new ArgumentNullException (nameof (stream)); - var attachment = await CreateAttachmentAsync (GetMimeType (fileName), fileName, stream, true, cancellationToken).ConfigureAwait (false); + var attachment = await CreateAttachmentAsync (GetMimeType (fileName), true, fileName, stream, true, cancellationToken).ConfigureAwait (false); attachments.Add (attachment); @@ -692,7 +706,7 @@ public async Task AddAsync (string fileName, ContentType contentType throw new ArgumentNullException (nameof (contentType)); using (var stream = File.OpenRead (fileName)) { - var attachment = await CreateAttachmentAsync (contentType, fileName, stream, true, cancellationToken).ConfigureAwait (false); + var attachment = await CreateAttachmentAsync (contentType, false, fileName, stream, true, cancellationToken).ConfigureAwait (false); attachments.Add (attachment); @@ -791,7 +805,7 @@ public async Task AddAsync (string fileName, CancellationToken cance throw new ArgumentException ("The specified file path is empty.", nameof (fileName)); using (var stream = File.OpenRead (fileName)) { - var attachment = await CreateAttachmentAsync (GetMimeType (fileName), fileName, stream, true, cancellationToken).ConfigureAwait (false); + var attachment = await CreateAttachmentAsync (GetMimeType (fileName), true, fileName, stream, true, cancellationToken).ConfigureAwait (false); attachments.Add (attachment); diff --git a/UnitTests/AttachmentCollectionTests.cs b/UnitTests/AttachmentCollectionTests.cs index 1c09655b46..7b638d7d00 100644 --- a/UnitTests/AttachmentCollectionTests.cs +++ b/UnitTests/AttachmentCollectionTests.cs @@ -515,6 +515,54 @@ public async Task TestAddEmailMessageAsync () attachments.Clear (true); } + [Test] + public void TestAddEmailMessageFallback () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var attachments = new AttachmentCollection (); + MimeEntity attachment; + + using (var stream = File.OpenRead (fileName)) + attachment = attachments.Add ("message.eml", stream); + + Assert.That (attachment.ContentType.MimeType, Is.EqualTo ("application/octet-stream")); + Assert.That (attachment.ContentType.Name, Is.EqualTo ("message.eml")); + Assert.That (attachment.ContentDisposition, Is.Not.Null); + Assert.That (attachment.ContentDisposition.Disposition, Is.EqualTo ("attachment")); + Assert.That (attachment.ContentDisposition.FileName, Is.EqualTo ("message.eml")); + Assert.That (attachments.Count, Is.EqualTo (1)); + + Assert.That (attachments.Contains (attachment), Is.True, "Contains"); + Assert.That (attachments.IndexOf (attachment), Is.EqualTo (0), "IndexOf"); + Assert.That (attachments.Remove (attachment), Is.True, "Remove"); + Assert.That (attachments.Count, Is.EqualTo (0)); + attachments.Clear (true); + } + + [Test] + public async Task TestAddEmailMessageFallbackAsync () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var attachments = new AttachmentCollection (); + MimeEntity attachment; + + using (var stream = File.OpenRead (fileName)) + attachment = await attachments.AddAsync ("message.eml", stream); + + Assert.That (attachment.ContentType.MimeType, Is.EqualTo ("application/octet-stream")); + Assert.That (attachment.ContentType.Name, Is.EqualTo ("message.eml")); + Assert.That (attachment.ContentDisposition, Is.Not.Null); + Assert.That (attachment.ContentDisposition.Disposition, Is.EqualTo ("attachment")); + Assert.That (attachment.ContentDisposition.FileName, Is.EqualTo ("message.eml")); + Assert.That (attachments.Count, Is.EqualTo (1)); + + Assert.That (attachments.Contains (attachment), Is.True, "Contains"); + Assert.That (attachments.IndexOf (attachment), Is.EqualTo (0), "IndexOf"); + Assert.That (attachments.Remove (attachment), Is.True, "Remove"); + Assert.That (attachments.Count, Is.EqualTo (0)); + attachments.Clear (true); + } + [Test] public void TestAddInlineEmailMessage () {