File: System\Net\Mime\MimeWriter.cs
Web Access
Project: src\src\libraries\System.Net.Mail\src\System.Net.Mail.csproj (System.Net.Mail)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
 
namespace System.Net.Mime
{
    /// <summary>
    /// Provides an abstraction for writing a MIME multi-part
    /// message.
    /// </summary>
    internal sealed class MimeWriter : BaseWriter
    {
        private readonly byte[] _boundaryBytes;
        private bool _writeBoundary = true;
 
        internal MimeWriter(Stream stream, string boundary)
            : base(stream, false) // Unnecessary, the underlying MailWriter stream already encodes dots
        {
            ArgumentNullException.ThrowIfNull(boundary);
 
            _boundaryBytes = Encoding.ASCII.GetBytes(boundary);
        }
 
        internal override void WriteHeaders(NameValueCollection headers, bool allowUnicode)
        {
            ArgumentNullException.ThrowIfNull(headers);
 
            foreach (string key in headers)
                WriteHeader(key, headers[key]!, allowUnicode);
        }
 
        #region Cleanup
 
        internal IAsyncResult BeginClose(AsyncCallback? callback, object? state)
        {
            MultiAsyncResult multiResult = new MultiAsyncResult(this, callback, state);
 
            Close(multiResult);
 
            multiResult.CompleteSequence();
 
            return multiResult;
        }
 
        internal void EndClose(IAsyncResult result)
        {
            MultiAsyncResult.End(result);
 
            _stream.Close();
        }
 
        internal override void Close()
        {
            Close(null);
 
            _stream.Close();
        }
 
        private void Close(MultiAsyncResult? multiResult)
        {
            _bufferBuilder.Append("\r\n--"u8);
            _bufferBuilder.Append(_boundaryBytes);
            _bufferBuilder.Append("--\r\n"u8);
            Flush(multiResult);
        }
 
        /// <summary>
        /// Called when the current stream is closed.  Allows us to
        /// prepare for the next message part.
        /// </summary>
        /// <param name="sender">Sender of the close event</param>
        /// <param name="args">Event args (not used)</param>
        protected override void OnClose(object? sender, EventArgs args)
        {
            if (_contentStream != sender)
                return; // may have called WriteHeader
 
            _contentStream.Flush();
            _contentStream = null!;
            _writeBoundary = true;
 
            _isInContent = false;
        }
 
        #endregion Cleanup
 
        /// <summary>
        /// Writes the boundary sequence if required.
        /// </summary>
        protected override void CheckBoundary()
        {
            if (_writeBoundary)
            {
                _bufferBuilder.Append("\r\n--"u8);
                _bufferBuilder.Append(_boundaryBytes);
                _bufferBuilder.Append("\r\n"u8);
                _writeBoundary = false;
            }
        }
    }
}