예제 #1
0
        /// <summary>
        /// Load a <see cref="MimeEntity"/> from the specified content stream.
        /// </summary>
        /// <remarks>
        /// This method is mostly meant for use with APIs such as <see cref="System.Net.HttpWebResponse"/>
        /// where the headers are parsed separately from the content.
        /// </remarks>
        /// <returns>The parsed MIME entity.</returns>
        /// <param name="options">The parser options.</param>
        /// <param name="contentType">The Content-Type of the stream.</param>
        /// <param name="content">The content stream.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="options"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="contentType"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="content"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.FormatException">
        /// There was an error parsing the entity.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        public static MimeEntity Load(ParserOptions options, ContentType contentType, Stream content, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            if (contentType == null)
            {
                throw new ArgumentNullException("contentType");
            }

            if (content == null)
            {
                throw new ArgumentNullException("content");
            }

            var format = FormatOptions.CloneDefault();

            format.NewLineFormat = NewLineFormat.Dos;

            var encoded = contentType.Encode(format, Encoding.UTF8);
            var header  = string.Format("Content-Type:{0}\r\n", encoded);
            var chained = new ChainedStream();

            chained.Add(new MemoryStream(Encoding.UTF8.GetBytes(header), false));
            chained.Add(content);

            return(Load(options, chained, cancellationToken));
        }
예제 #2
0
        /// <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.CloneDefault();

            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;
        }