public void TestReassemble () { var message1 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.1.msg.txt")); var message2 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.2.msg.txt")); Assert.IsNotNull (message1, "Failed to parse message-partial.1.msg"); Assert.IsNotNull (message2, "Failed to parse message-partial.2.msg"); Assert.IsTrue (message1.Body is MessagePartial, "The body of message-partial.1.msg is not a message/partial"); Assert.IsTrue (message2.Body is MessagePartial, "The body of message-partial.2.msg is not a message/partial"); var partials = new MessagePartial[] { (MessagePartial) message1.Body, (MessagePartial) message2.Body }; Assert.Throws<ArgumentNullException> (() => MessagePartial.Join (null, partials)); Assert.Throws<ArgumentNullException> (() => MessagePartial.Join (null)); var message = MessagePartial.Join (partials); Assert.IsNotNull (message, "Failed to reconstruct the message"); Assert.AreEqual ("{15_3779; Victoria & Cherry}: suzeFan - 2377h003.jpg", message.Subject, "Subjects do not match"); Assert.IsTrue (message.Body is Multipart, "Parsed message body is not a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Multipart does not contain the expected number of parts"); var part = multipart[1] as MimePart; Assert.IsNotNull (part, "Second part is null or not a MimePart"); Assert.IsTrue (part.ContentType.IsMimeType ("image", "jpeg"), "Attachment is not an image/jpeg"); Assert.AreEqual ("2377h003.jpg", part.FileName, "Attachment filename is not the expected value"); }
static int PartialCompare(MessagePartial partial1, MessagePartial partial2) { if (!partial1.Number.HasValue || !partial2.Number.HasValue || partial1.Id != partial2.Id) { throw new ArgumentException("Partial messages have mismatching identifiers.", "partials"); } return(partial1.Number.Value - partial2.Number.Value); }
static int PartialCompare(MessagePartial partial1, MessagePartial partial2) { if (!partial1.Number.HasValue || !partial2.Number.HasValue || partial1.Id != partial2.Id) { throw new ArgumentException("partial"); } return(partial1.Number.Value - partial2.Number.Value); }
/// <summary> /// Splits the specified message into multiple messages. /// </summary> /// <remarks> /// Splits the specified message into multiple messages, each with a /// message/partial body no larger than the max size specified. /// </remarks> /// <returns>An enumeration of partial messages.</returns> /// <param name="message">The message.</param> /// <param name="maxSize">The maximum size for each message body.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="message"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="maxSize"/> is less than <c>1</c>. /// </exception> public static IEnumerable <MimeMessage> Split(MimeMessage message, int maxSize) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (maxSize < 1) { throw new ArgumentOutOfRangeException(nameof(maxSize)); } var options = FormatOptions.Default.Clone(); foreach (HeaderId id in Enum.GetValues(typeof(HeaderId))) { switch (id) { case HeaderId.Subject: case HeaderId.MessageId: case HeaderId.Encrypted: case HeaderId.MimeVersion: case HeaderId.ContentAlternative: case HeaderId.ContentBase: case HeaderId.ContentClass: case HeaderId.ContentDescription: case HeaderId.ContentDisposition: case HeaderId.ContentDuration: case HeaderId.ContentFeatures: case HeaderId.ContentId: case HeaderId.ContentIdentifier: case HeaderId.ContentLanguage: case HeaderId.ContentLength: case HeaderId.ContentLocation: case HeaderId.ContentMd5: case HeaderId.ContentReturn: case HeaderId.ContentTransferEncoding: case HeaderId.ContentTranslationType: case HeaderId.ContentType: break; default: options.HiddenHeaders.Add(id); break; } } var memory = new MemoryStream(); message.WriteTo(options, memory); memory.Seek(0, SeekOrigin.Begin); if (memory.Length <= maxSize) { memory.Dispose(); yield return(message); yield break; } var streams = new List <Stream> (); #if !NETSTANDARD1_3 && !NETSTANDARD1_6 var buf = memory.GetBuffer(); #else var buf = memory.ToArray(); #endif long startIndex = 0; while (startIndex < memory.Length) { // Preferably, we'd split on whole-lines if we can, // but if that's not possible, split on max size long endIndex = Math.Min(memory.Length, startIndex + maxSize); if (endIndex < memory.Length) { long ebx = endIndex; while (ebx > (startIndex + 1) && buf[ebx] != (byte)'\n') { ebx--; } if (buf[ebx] == (byte)'\n') { endIndex = ebx + 1; } } streams.Add(new BoundStream(memory, startIndex, endIndex, true)); startIndex = endIndex; } var msgid = message.MessageId ?? MimeUtils.GenerateMessageId(); int number = 1; foreach (var stream in streams) { var part = new MessagePartial(msgid, number++, streams.Count) { Content = new MimeContent(stream) }; var submessage = CloneMessage(message); submessage.MessageId = MimeUtils.GenerateMessageId(); submessage.Body = part; yield return(submessage); } yield break; }
/// <summary> /// Visit the message/partial MIME entity. /// </summary> /// <remarks> /// Visits the message/partial MIME entity. /// </remarks> /// <param name="entity">The message/partial MIME entity.</param> protected internal virtual void VisitMessagePartial(MessagePartial entity) { VisitMimePart(entity); }
static int PartialCompare(MessagePartial partial1, MessagePartial partial2) { if (!partial1.Number.HasValue || !partial2.Number.HasValue || partial1.Id != partial2.Id) throw new ArgumentException ("partial"); return partial1.Number.Value - partial2.Number.Value; }
/// <summary> /// Split the specified message into multiple messages, each with a /// message/partial body no larger than the max size specified. /// </summary> /// <param name="message">The message.</param> /// <param name="maxSize">The maximum size for each message body.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="message"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="maxSize"/> is less than <c>1</c>. /// </exception> public static IEnumerable<MimeMessage> Split(MimeMessage message, int maxSize) { if (message == null) throw new ArgumentNullException ("message"); if (maxSize < 1) throw new ArgumentOutOfRangeException ("maxSize"); using (var memory = new MemoryStream ()) { message.WriteTo (memory); memory.Seek (0, SeekOrigin.Begin); if (memory.Length <= maxSize) { yield return message; yield break; } var streams = new List<Stream> (); var buf = memory.GetBuffer (); long startIndex = 0; while (startIndex < memory.Length) { // Preferably, we'd split on whole-lines if we can, // but if that's not possible, split on max size long endIndex = Math.Min (memory.Length, startIndex + maxSize); if (endIndex < memory.Length) { long ebx = endIndex; while (ebx > (startIndex + 1) && buf[ebx] != (byte) '\n') ebx--; if (buf[ebx] == (byte) '\n') endIndex = ebx + 1; } streams.Add (new BoundStream (memory, startIndex, endIndex, true)); startIndex = endIndex; } var id = message.MessageId ?? MimeUtils.GenerateMessageId (); int number = 1; foreach (var stream in streams) { var part = new MessagePartial (id, number++, streams.Count); part.ContentObject = new ContentObject (stream, ContentEncoding.Default); var submessage = CloneMessage (message); submessage.MessageId = MimeUtils.GenerateMessageId (); submessage.Body = part; yield return submessage; } } yield break; }
/// <summary> /// Visit the message/partial MIME entity. /// </summary> /// <remarks> /// Visits the message/partial MIME entity. /// </remarks> /// <param name="entity">The message/partial MIME entity.</param> protected internal virtual void VisitMessagePartial (MessagePartial entity) { VisitMimePart (entity); }
/// <summary> /// Splits the specified message into multiple messages. /// </summary> /// <remarks> /// Splits the specified message into multiple messages, each with a /// message/partial body no larger than the max size specified. /// </remarks> /// <returns>An enumeration of partial messages.</returns> /// <param name="message">The message.</param> /// <param name="maxSize">The maximum size for each message body.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="message"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="maxSize"/> is less than <c>1</c>. /// </exception> public static IEnumerable <MimeMessage> Split(MimeMessage message, int maxSize) { if (message == null) { throw new ArgumentNullException("message"); } if (maxSize < 1) { throw new ArgumentOutOfRangeException("maxSize"); } using (var memory = new MemoryStream()) { message.WriteTo(memory); memory.Seek(0, SeekOrigin.Begin); if (memory.Length <= maxSize) { yield return(message); yield break; } var streams = new List <Stream> (); #if PORTABLE var buf = memory.ToArray(); #else var buf = memory.GetBuffer(); #endif long startIndex = 0; while (startIndex < memory.Length) { // Preferably, we'd split on whole-lines if we can, // but if that's not possible, split on max size long endIndex = Math.Min(memory.Length, startIndex + maxSize); if (endIndex < memory.Length) { long ebx = endIndex; while (ebx > (startIndex + 1) && buf[ebx] != (byte)'\n') { ebx--; } if (buf[ebx] == (byte)'\n') { endIndex = ebx + 1; } } streams.Add(new BoundStream(memory, startIndex, endIndex, true)); startIndex = endIndex; } var id = message.MessageId ?? MimeUtils.GenerateMessageId(); int number = 1; foreach (var stream in streams) { var part = new MessagePartial(id, number++, streams.Count); part.ContentObject = new ContentObject(stream, ContentEncoding.Default); var submessage = CloneMessage(message); submessage.MessageId = MimeUtils.GenerateMessageId(); submessage.Body = part; yield return(submessage); } } yield break; }
public void TestSplit () { var message1 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.1.msg.txt")); var message2 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.2.msg.txt")); var partials = new MessagePartial[] { (MessagePartial) message1.Body, (MessagePartial) message2.Body }; var message = MessagePartial.Join (partials); var split = MessagePartial.Split (message, 1024 * 16).ToList (); var parts = new List<MessagePartial> (); Assert.AreEqual (10, split.Count, "Unexpected count"); for (int i = 0; i < split.Count; i++) { parts.Add ((MessagePartial) split[i].Body); Assert.AreEqual (10, parts[i].Total, "Total"); Assert.AreEqual (i + 1, parts[i].Number, "Number"); } var combined = MessagePartial.Join (parts); using (var stream = new MemoryStream ()) { var options = FormatOptions.Default.Clone (); options.NewLineFormat = NewLineFormat.Unix; message.WriteTo (options, stream); var bytes0 = new byte[stream.Position]; Array.Copy (stream.GetBuffer (), 0, bytes0, 0, (int) stream.Position); stream.Position = 0; combined.WriteTo (options, stream); var bytes1 = new byte[stream.Position]; Array.Copy (stream.GetBuffer (), 0, bytes1, 0, (int) stream.Position); Assert.AreEqual (bytes0.Length, bytes1.Length, "bytes"); for (int i = 0; i < bytes0.Length; i++) Assert.AreEqual (bytes0[i], bytes1[i], "bytes[{0}]", i); } }