File: net\System\Net\mail\MimeWriter.cs
Project: ndp\fx\src\System.csproj (System)
//-----------------------------------------------------------------------------
// <copyright file="MimeWriter.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------------
 
namespace System.Net.Mime
{
    using System;
    using System.IO;
    using System.Text;
    using System.Collections.Specialized;
 
    /// <summary>
    /// Provides an abstraction for writing a MIME multi-part
    /// message.
    /// </summary>
    internal class MimeWriter:BaseWriter
    {
        private static byte[] DASHDASH = new byte[] { (byte)'-', (byte)'-' };
 
        private byte[] boundaryBytes;
        private bool writeBoundary = true;
 
        internal MimeWriter(Stream stream, string boundary)
            : base(stream, false) // Unnecessary, the underlying MailWriter stream already encodes dots
        {
            if (boundary == null)
                throw new ArgumentNullException("boundary");
 
            this.boundaryBytes = Encoding.ASCII.GetBytes(boundary);
        }
 
        internal override void WriteHeaders(NameValueCollection headers, bool allowUnicode)
        {
            if (headers == null)
                throw new ArgumentNullException("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);
 
            this.stream.Close();
        }
 
        internal override void Close()
        {
            Close(null);
 
            this.stream.Close();
        }
 
        void Close(MultiAsyncResult multiResult)
        {
            this.bufferBuilder.Append(CRLF);
            this.bufferBuilder.Append(DASHDASH);
            this.bufferBuilder.Append(this.boundaryBytes);
            this.bufferBuilder.Append(DASHDASH);
            this.bufferBuilder.Append(CRLF);
            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 (this.contentStream != sender)
                return; // may have called WriteHeader
 
            this.contentStream.Flush();
            this.contentStream = null;
            this.writeBoundary = true;
 
            this.isInContent = false;
        }
 
        #endregion Cleanup
 
        /// <summary>
        /// Writes the boundary sequence if required.
        /// </summary>
        protected override void CheckBoundary()
        {
            if (this.writeBoundary)
            {
                this.bufferBuilder.Append(CRLF);
                this.bufferBuilder.Append(DASHDASH);
                this.bufferBuilder.Append(this.boundaryBytes);
                this.bufferBuilder.Append(CRLF);
                this.writeBoundary = false;
            }
        }
    }
}