Пример #1
0
        public void TestInvalidAtNoDomainMessageId()
        {
            // https://github.com/jstedfast/MimeKit/issues/102
            var msgid = MimeUtils.EnumerateReferences("<local-part@>").FirstOrDefault();

            Assert.AreEqual("local-part@", msgid);
        }
Пример #2
0
        public void TestArgumentExceptions()
        {
            var buffer = new byte[1024];

            Assert.Throws <ArgumentNullException> (() => MimeUtils.GenerateMessageId(null), "MimeUtils.GenerateMessageId (null)");
            Assert.Throws <ArgumentException> (() => MimeUtils.GenerateMessageId(string.Empty), "MimeUtils.GenerateMessageId (string.Empty)");

            Assert.Throws <ArgumentNullException> (() => MimeUtils.EnumerateReferences(null), "MimeUtils.EnumerateReferences (null)");
            Assert.Throws <ArgumentNullException> (() => MimeUtils.EnumerateReferences(null, 0, 0).FirstOrDefault(), "MimeUtils.EnumerateReferences (null, 0, 0)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.EnumerateReferences(buffer, -1, 0).FirstOrDefault(), "MimeUtils.EnumerateReferences (buffer, -1, 0)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.EnumerateReferences(buffer, buffer.Length + 1, 0).FirstOrDefault(), "MimeUtils.EnumerateReferences (buffer, buffer.Length + 1, 0)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.EnumerateReferences(buffer, 0, -1).FirstOrDefault(), "MimeUtils.EnumerateReferences (buffer, 0, -1)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.EnumerateReferences(buffer, 0, buffer.Length + 1).FirstOrDefault(), "MimeUtils.EnumerateReferences (buffer, 0, buffer.Length + 1)");

            Assert.Throws <ArgumentNullException> (() => MimeUtils.ParseMessageId(null), "MimeUtils.ParseMessageId (null)");
            Assert.Throws <ArgumentNullException> (() => MimeUtils.ParseMessageId(null, 0, 0), "MimeUtils.ParseMessageId (null, 0, 0)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.ParseMessageId(buffer, -1, 0), "MimeUtils.ParseMessageId (buffer, -1, 0)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.ParseMessageId(buffer, buffer.Length + 1, 0), "MimeUtils.ParseMessageId (buffer, buffer.Length + 1, 0)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.ParseMessageId(buffer, 0, -1), "MimeUtils.ParseMessageId (buffer, 0, -1)");
            Assert.Throws <ArgumentOutOfRangeException> (() => MimeUtils.ParseMessageId(buffer, 0, buffer.Length + 1), "MimeUtils.ParseMessageId (buffer, 0, buffer.Length + 1)");

            Assert.Throws <ArgumentNullException> (() => MimeUtils.AppendQuoted(null, "text"), "MimeUtils.AppendQuoted (null, value)");
            Assert.Throws <ArgumentNullException> (() => MimeUtils.AppendQuoted(new StringBuilder(), null), "MimeUtils.AppendQuoted (builder, null)");
            Assert.Throws <ArgumentNullException> (() => MimeUtils.Quote(null), "MimeUtils.Quote (null)");
            Assert.Throws <ArgumentNullException> (() => MimeUtils.Unquote(null), "MimeUtils.Unquote (null)");
        }
Пример #3
0
        /// <summary>
        /// Parses the ENVELOPE parenthesized list.
        /// </summary>
        /// <returns>The envelope.</returns>
        /// <param name="engine">The IMAP engine.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        public static Envelope ParseEnvelope(ImapEngine engine, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken (cancellationToken);
            string nstring;

            if (token.Type != ImapTokenType.OpenParen)
                throw ImapEngine.UnexpectedToken (token, false);

            var envelope = new Envelope ();
            envelope.Date = ParseEnvelopeDate (engine, cancellationToken);
            envelope.Subject = ReadNStringToken (engine, true, cancellationToken);
            ParseEnvelopeAddressList (envelope.From, engine, cancellationToken);
            ParseEnvelopeAddressList (envelope.Sender, engine, cancellationToken);
            ParseEnvelopeAddressList (envelope.ReplyTo, engine, cancellationToken);
            ParseEnvelopeAddressList (envelope.To, engine, cancellationToken);
            ParseEnvelopeAddressList (envelope.Cc, engine, cancellationToken);
            ParseEnvelopeAddressList (envelope.Bcc, engine, cancellationToken);

            if ((nstring = ReadNStringToken (engine, false, cancellationToken)) != null)
                envelope.InReplyTo = MimeUtils.EnumerateReferences (nstring).FirstOrDefault ();

            if ((nstring = ReadNStringToken (engine, false, cancellationToken)) != null)
                envelope.MessageId = MimeUtils.EnumerateReferences (nstring).FirstOrDefault ();

            token = engine.ReadToken (cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
                throw ImapEngine.UnexpectedToken (token, false);

            return envelope;
        }
Пример #4
0
        static byte[] EncodeReferencesHeader(ParserOptions options, FormatOptions format, Encoding charset, string field, string value)
        {
            var encoded    = new StringBuilder();
            int lineLength = field.Length + 1;
            int count      = 0;

            foreach (var reference in MimeUtils.EnumerateReferences(value))
            {
                if (count > 0 && lineLength + reference.Length + 3 > format.MaxLineLength)
                {
                    encoded.Append(format.NewLine);
                    encoded.Append('\t');
                    lineLength = 1;
                    count      = 0;
                }
                else
                {
                    encoded.Append(' ');
                    lineLength++;
                }

                encoded.Append('<').Append(reference).Append('>');
                lineLength += reference.Length + 2;
                count++;
            }

            encoded.Append(format.NewLine);

            return(charset.GetBytes(encoded.ToString()));
        }
        MessageSummary MakeThreadable(ref int index, string subject, string msgid, string date, string refs)
        {
            DateTimeOffset value;

            DateUtils.TryParse(date, out value);

            var summary = new MessageSummary(index++);

            summary.UniqueId   = new UniqueId((uint)summary.Index);
            summary.Envelope   = new Envelope();
            summary.References = new MessageIdList();
            if (refs != null)
            {
                foreach (var id in refs.Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    summary.References.Add(id);
                }
            }
            summary.Envelope.MessageId = MimeUtils.EnumerateReferences(msgid).FirstOrDefault();
            summary.Envelope.Subject   = subject;
            summary.Envelope.Date      = value;
            summary.Size = 0;

            return(summary);
        }
Пример #6
0
        /// <summary>
        /// Called when the headers change in some way.
        /// </summary>
        /// <remarks>
        /// Whenever a header is changed, this method will be called in order to allow
        /// custom <see cref="MimeEntity"/> subclasses to update their state.
        /// </remarks>
        /// <param name="action">The type of change.</param>
        /// <param name="header">The header being added, changed or removed.</param>
        protected virtual void OnHeadersChanged(HeaderListChangedAction action, Header header)
        {
            switch (action)
            {
            case HeaderListChangedAction.Added:
            case HeaderListChangedAction.Changed:
                switch (header.Id)
                {
                case HeaderId.ContentDisposition:
                    if (disposition != null)
                    {
                        disposition.Changed -= ContentDispositionChanged;
                    }

                    if (ContentDisposition.TryParse(Headers.Options, header.RawValue, out disposition))
                    {
                        disposition.Changed += ContentDispositionChanged;
                    }
                    break;

                case HeaderId.ContentId:
                    contentId = MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length).FirstOrDefault();
                    break;
                }
                break;

            case HeaderListChangedAction.Removed:
                switch (header.Id)
                {
                case HeaderId.ContentDisposition:
                    if (disposition != null)
                    {
                        disposition.Changed -= ContentDispositionChanged;
                    }

                    disposition = null;
                    break;

                case HeaderId.ContentId:
                    contentId = null;
                    break;
                }
                break;

            case HeaderListChangedAction.Cleared:
                if (disposition != null)
                {
                    disposition.Changed -= ContentDispositionChanged;
                }

                disposition = null;
                contentId   = null;
                break;

            default:
                throw new ArgumentOutOfRangeException("action");
            }
        }
Пример #7
0
        /// <summary>
        /// Gets the index of the body part matching the specified URI.
        /// </summary>
        /// <remarks>
        /// <para>Finds the index of the body part matching the specified URI, if it exists.</para>
        /// <para>If the URI scheme is <c>"cid"</c>, then matching is performed based on the Content-Id header
        /// values, otherwise the Content-Location headers are used. If the provided URI is absolute and a child
        /// part's Content-Location is relative, then then the child part's Content-Location URI will be combined
        /// with the value of its Content-Base header, if available, otherwise it will be combined with the
        /// multipart/related part's Content-Base header in order to produce an absolute URI that can be
        /// compared with the provided absolute URI.</para>
        /// </remarks>
        /// <returns>The index of the part matching the specified URI if found; otherwise <c>-1</c>.</returns>
        /// <param name="uri">The URI of the body part.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        public int IndexOf(Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            bool cid = uri.IsAbsoluteUri && uri.Scheme.ToLowerInvariant() == "cid";

            for (int index = 0; index < Count; index++)
            {
                var bodyPart = this[index] as BodyPartBasic;

                if (bodyPart == null)
                {
                    continue;
                }

                if (uri.IsAbsoluteUri)
                {
                    if (cid)
                    {
                        if (!string.IsNullOrEmpty(bodyPart.ContentId))
                        {
                            var id = MimeUtils.EnumerateReferences(bodyPart.ContentId).FirstOrDefault();

                            if (id == uri.AbsolutePath)
                            {
                                return(index);
                            }
                        }
                    }
                    else if (bodyPart.ContentLocation != null)
                    {
                        Uri absolute;

                        if (!bodyPart.ContentLocation.IsAbsoluteUri)
                        {
                            continue;
                        }

                        absolute = bodyPart.ContentLocation;

                        if (absolute == uri)
                        {
                            return(index);
                        }
                    }
                }
                else if (bodyPart.ContentLocation == uri)
                {
                    return(index);
                }
            }

            return(-1);
        }
Пример #8
0
        /// <summary>
        /// Gets the index of the body part matching the specified URI.
        /// </summary>
        /// <remarks>
        /// <para>Finds the index of the body part matching the specified URI, if it exists.</para>
        /// <para>If the URI scheme is <c>"cid"</c>, then matching is performed based on the Content-Id header
        /// values, otherwise the Content-Location headers are used. If the provided URI is absolute and a child
        /// part's Content-Location is relative, then then the child part's Content-Location URI will be combined
        /// with the value of its Content-Base header, if available, otherwise it will be combined with the
        /// multipart/related part's Content-Base header in order to produce an absolute URI that can be
        /// compared with the provided absolute URI.</para>
        /// </remarks>
        /// <returns>The index of the part matching the specified URI if found; otherwise <c>-1</c>.</returns>
        /// <param name="uri">The URI of the body part.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        public int IndexOf(Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException(nameof(uri));
            }

            bool cid = uri.IsAbsoluteUri && uri.Scheme.ToLowerInvariant() == "cid";

            for (int index = 0; index < Count; index++)
            {
                var bodyPart = this[index] as BodyPartBasic;

                if (bodyPart == null)
                {
                    continue;
                }

                if (uri.IsAbsoluteUri)
                {
                    if (cid)
                    {
                        if (!string.IsNullOrEmpty(bodyPart.ContentId))
                        {
                            // Note: we might have a Content-Id in the form "<*****@*****.**>", so attempt to decode it
                            var id = MimeUtils.EnumerateReferences(bodyPart.ContentId).FirstOrDefault() ?? bodyPart.ContentId;

                            if (id == uri.AbsolutePath)
                            {
                                return(index);
                            }
                        }
                    }
                    else if (bodyPart.ContentLocation != null)
                    {
                        if (!bodyPart.ContentLocation.IsAbsoluteUri)
                        {
                            continue;
                        }

                        if (bodyPart.ContentLocation == uri)
                        {
                            return(index);
                        }
                    }
                }
                else if (bodyPart.ContentLocation == uri)
                {
                    return(index);
                }
            }

            return(-1);
        }
Пример #9
0
        public void TestParseGoodReferences()
        {
            for (int i = 0; i < GoodReferences.Length; i += 2)
            {
                var reference = MimeUtils.EnumerateReferences(GoodReferences[i]).FirstOrDefault();

                Assert.AreEqual(GoodReferences[i + 1], reference, "Incorrectly parsed reference '{0}'.", GoodReferences[i]);

                reference = MimeUtils.ParseMessageId(GoodReferences[i]);

                Assert.AreEqual(GoodReferences[i + 1], reference, "Incorrectly parsed message-id '{0}'.", GoodReferences[i]);
            }
        }
Пример #10
0
        public void TestParseBrokenReferences()
        {
            for (int i = 0; i < BrokenReferences.Length; i++)
            {
                var reference = MimeUtils.EnumerateReferences(BrokenReferences[i]).FirstOrDefault();

                Assert.IsNull(reference, "MimeUtils.EnumerateReferences(\"{0}\")", BrokenReferences[i]);

                reference = MimeUtils.ParseMessageId(BrokenReferences[i]);

                Assert.IsNull(reference, "MimeUtils.ParseMessageId (\"{0}\")", BrokenReferences[i]);
            }
        }
Пример #11
0
        public void TestParsingObsoleteInReplyToSyntax()
        {
            var obsolete = "Joe Sixpack's message sent on Mon, 17 Jan 1994 11:14:55 -0500 <*****@*****.**>";
            var msgid    = MimeUtils.EnumerateReferences(obsolete).FirstOrDefault();

            Assert.IsNotNull(msgid, "The parsed msgid token should not be null");
            Assert.AreEqual("*****@*****.**", msgid, "The parsed msgid does not match");

            obsolete = "<*****@*****.**> as sent on Mon, 17 Jan 1994 11:14:55 -0500";
            msgid    = MimeUtils.EnumerateReferences(obsolete).FirstOrDefault();

            Assert.IsNotNull(msgid, "The parsed msgid token should not be null");
            Assert.AreEqual("*****@*****.**", msgid, "The parsed msgid does not match");
        }
Пример #12
0
        int GetRootIndex()
        {
            string start = ContentType.Parameters["start"];

            if (start == null)
            {
                return(-1);
            }

            string contentId;

            if ((contentId = MimeUtils.EnumerateReferences(start).FirstOrDefault()) == null)
            {
                contentId = start;
            }

            var cid = new Uri(string.Format("cid:{0}", contentId));

            return(IndexOf(cid));
        }
Пример #13
0
        int GetRootIndex()
        {
            var start = ContentType.Parameters["start"];

            if (start != null)
            {
                string contentId;

                if ((contentId = MimeUtils.EnumerateReferences(start).FirstOrDefault()) == null)
                {
                    contentId = start;
                }

                var cid = new Uri(string.Format("cid:{0}", contentId));

                return(IndexOf(cid));
            }

            var type = ContentType.Parameters["type"];

            if (type == null)
            {
                return(-1);
            }

            for (int index = 0; index < Count; index++)
            {
                var mimeType = this[index].ContentType.MimeType;

                if (mimeType.Equals(type, StringComparison.OrdinalIgnoreCase))
                {
                    return(index);
                }
            }

            return(-1);
        }
Пример #14
0
        static BodyPart GetMultipartRelatedRoot(BodyPartMultipart related)
        {
            string start = related.ContentType.Parameters["start"];
            string contentId;

            if (start == null)
            {
                return(related.BodyParts.Count > 0 ? related.BodyParts[0] : null);
            }

            if ((contentId = MimeUtils.EnumerateReferences(start).FirstOrDefault()) == null)
            {
                contentId = start;
            }

            var cid = new Uri(string.Format("cid:{0}", contentId));

            for (int i = 0; i < related.BodyParts.Count; i++)
            {
                var basic = related.BodyParts[i] as BodyPartBasic;

                if (basic != null && (basic.ContentId == contentId || basic.ContentLocation == cid))
                {
                    return(basic);
                }

                var multipart = related.BodyParts[i] as BodyPartMultipart;

                if (multipart != null && multipart.ContentLocation == cid)
                {
                    return(multipart);
                }
            }

            return(null);
        }
Пример #15
0
        void ReloadHeader(HeaderId id, string field)
        {
            if (id == HeaderId.Unknown)
            {
                return;
            }

            if (id == HeaderId.References)
            {
                references.Changed -= ReferencesChanged;
                references.Clear();
                references.Changed += ReferencesChanged;
            }
            else if (id == HeaderId.InReplyTo)
            {
                inreplyto = null;
            }

            foreach (var header in Headers)
            {
                if (header.Id != id)
                {
                    continue;
                }

                switch (id)
                {
                case HeaderId.MimeVersion:
                    if (MimeUtils.TryParseVersion(header.RawValue, 0, header.RawValue.Length, out version))
                    {
                        return;
                    }
                    break;

                case HeaderId.References:
                    references.Changed -= ReferencesChanged;
                    foreach (var msgid in MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length))
                    {
                        references.Add(msgid);
                    }
                    references.Changed += ReferencesChanged;
                    break;

                case HeaderId.InReplyTo:
                    inreplyto = MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length).FirstOrDefault();
                    break;

                case HeaderId.MessageId:
                    messageId = MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length).FirstOrDefault();
                    if (messageId != null)
                    {
                        return;
                    }
                    break;

                case HeaderId.Date:
                    if (DateUtils.TryParseDateTime(header.RawValue, 0, header.RawValue.Length, out date))
                    {
                        return;
                    }
                    break;
                }
            }
        }
Пример #16
0
        public void TestInvalidNoDomainMessageId()
        {
            var msgid = MimeUtils.EnumerateReferences("<local-part>").FirstOrDefault();

            Assert.AreEqual("local-part", msgid);
        }
Пример #17
0
        /// <summary>
        /// Called when the headers change in some way.
        /// </summary>
        /// <remarks>
        /// <para>Whenever a header is added, changed, or removed, this method will
        /// be called in order to allow custom <see cref="MimeEntity"/> subclasses
        /// to update their state.</para>
        /// <para>Overrides of this method should call the base method so that their
        /// superclass may also update its own state.</para>
        /// </remarks>
        /// <param name="action">The type of change.</param>
        /// <param name="header">The header being added, changed or removed.</param>
        protected virtual void OnHeadersChanged(HeaderListChangedAction action, Header header)
        {
            string text;

            switch (action)
            {
            case HeaderListChangedAction.Added:
            case HeaderListChangedAction.Changed:
                switch (header.Id)
                {
                case HeaderId.ContentDisposition:
                    if (disposition != null)
                    {
                        disposition.Changed -= ContentDispositionChanged;
                    }

                    if (ContentDisposition.TryParse(Headers.Options, header.RawValue, out disposition))
                    {
                        disposition.Changed += ContentDispositionChanged;
                    }
                    break;

                case HeaderId.ContentLocation:
                    text = header.Value.Trim();

                    if (Uri.IsWellFormedUriString(text, UriKind.Absolute))
                    {
                        location = new Uri(text, UriKind.Absolute);
                    }
                    else if (Uri.IsWellFormedUriString(text, UriKind.Relative))
                    {
                        location = new Uri(text, UriKind.Relative);
                    }
                    else
                    {
                        location = null;
                    }
                    break;

                case HeaderId.ContentBase:
                    text = header.Value.Trim();

                    if (Uri.IsWellFormedUriString(text, UriKind.Absolute))
                    {
                        baseUri = new Uri(text, UriKind.Absolute);
                    }
                    else
                    {
                        baseUri = null;
                    }
                    break;

                case HeaderId.ContentId:
                    contentId = MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length).FirstOrDefault();
                    break;
                }
                break;

            case HeaderListChangedAction.Removed:
                switch (header.Id)
                {
                case HeaderId.ContentDisposition:
                    if (disposition != null)
                    {
                        disposition.Changed -= ContentDispositionChanged;
                    }

                    disposition = null;
                    break;

                case HeaderId.ContentLocation:
                    location = null;
                    break;

                case HeaderId.ContentBase:
                    baseUri = null;
                    break;

                case HeaderId.ContentId:
                    contentId = null;
                    break;
                }
                break;

            case HeaderListChangedAction.Cleared:
                if (disposition != null)
                {
                    disposition.Changed -= ContentDispositionChanged;
                }

                disposition = null;
                contentId   = null;
                location    = null;
                baseUri     = null;
                break;

            default:
                throw new ArgumentOutOfRangeException("action");
            }
        }
Пример #18
0
        internal static bool TryParse(string text, ref int index, out Envelope envelope)
        {
            InternetAddressList from, sender, replyto, to, cc, bcc;
            string         inreplyto, messageid, subject, nstring;
            DateTimeOffset?date = null;

            envelope = null;

            while (index < text.Length && text[index] == ' ')
            {
                index++;
            }

            if (index >= text.Length || text[index] != '(')
            {
                if (index + 3 <= text.Length && text.Substring(index, 3) == "NIL")
                {
                    index += 3;
                    return(true);
                }

                return(false);
            }

            index++;

            if (!TryParse(text, ref index, out nstring))
            {
                return(false);
            }

            if (nstring != null)
            {
                DateTimeOffset value;

                if (!DateUtils.TryParse(nstring, out value))
                {
                    return(false);
                }

                date = value;
            }

            if (!TryParse(text, ref index, out subject))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out from))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out sender))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out replyto))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out to))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out cc))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out bcc))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out inreplyto))
            {
                return(false);
            }

            if (!TryParse(text, ref index, out messageid))
            {
                return(false);
            }

            if (index >= text.Length || text[index] != ')')
            {
                return(false);
            }

            index++;

            envelope = new Envelope {
                Date      = date,
                Subject   = subject,
                From      = from,
                Sender    = sender,
                ReplyTo   = replyto,
                To        = to,
                Cc        = cc,
                Bcc       = bcc,
                InReplyTo = inreplyto != null?MimeUtils.EnumerateReferences(inreplyto).FirstOrDefault() ?? inreplyto : null,
                MessageId = messageid != null?MimeUtils.EnumerateReferences(messageid).FirstOrDefault() ?? messageid : null
            };

            return(true);
        }
Пример #19
0
        void HeadersChanged(object sender, HeaderListChangedEventArgs e)
        {
            InternetAddressList list;

            switch (e.Action)
            {
            case HeaderListChangedAction.Added:
                if (addresses.TryGetValue(e.Header.Field, out list))
                {
                    AddAddresses(e.Header, list);
                    break;
                }

                switch (e.Header.Id)
                {
                case HeaderId.MimeVersion:
                    MimeUtils.TryParseVersion(e.Header.RawValue, 0, e.Header.RawValue.Length, out version);
                    break;

                case HeaderId.References:
                    references.Changed -= ReferencesChanged;
                    foreach (var msgid in MimeUtils.EnumerateReferences(e.Header.RawValue, 0, e.Header.RawValue.Length))
                    {
                        references.Add(msgid);
                    }
                    references.Changed += ReferencesChanged;
                    break;

                case HeaderId.InReplyTo:
                    inreplyto = MimeUtils.EnumerateReferences(e.Header.RawValue, 0, e.Header.RawValue.Length).FirstOrDefault();
                    break;

                case HeaderId.MessageId:
                    messageId = MimeUtils.EnumerateReferences(e.Header.RawValue, 0, e.Header.RawValue.Length).FirstOrDefault();
                    break;

                case HeaderId.Date:
                    DateUtils.TryParseDateTime(e.Header.RawValue, 0, e.Header.RawValue.Length, out date);
                    break;
                }
                break;

            case HeaderListChangedAction.Changed:
            case HeaderListChangedAction.Removed:
                if (addresses.TryGetValue(e.Header.Field, out list))
                {
                    ReloadAddressList(e.Header.Field, list);
                    break;
                }

                ReloadHeader(e.Header.Id, e.Header.Field);
                break;

            case HeaderListChangedAction.Cleared:
                foreach (var kvp in addresses)
                {
                    kvp.Value.Changed -= InternetAddressListChanged;
                    kvp.Value.Clear();
                    kvp.Value.Changed += InternetAddressListChanged;
                }

                references.Changed -= ReferencesChanged;
                references.Clear();
                references.Changed += ReferencesChanged;

                inreplyto = null;
                messageId = null;
                version   = null;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }