コード例 #1
0
ファイル: TnefTests.cs プロジェクト: hugohallqvist/MimeKit
        static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder)
        {
            var prop = reader.TnefPropertyReader;

            while (prop.ReadNextProperty())
            {
                switch (prop.PropertyTag.Id)
                {
                case TnefPropertyId.InternetMessageId:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.MessageId = prop.ReadValueAsString();
                        Console.WriteLine("Message Property: {0} = {1}", prop.PropertyTag.Id, message.MessageId);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for Message-Id: {0}", prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.Subject:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.Subject = prop.ReadValueAsString();
                        Console.WriteLine("Message Property: {0} = {1}", prop.PropertyTag.Id, message.Subject);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for Subject: {0}", prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.RtfCompressed:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var rtf = new TextPart("rtf");
                        rtf.ContentType.Name = "body.rtf";

                        var converter = new RtfCompressedToRtf();
                        var content   = new MemoryStream();

                        using (var filtered = new FilteredStream(content)) {
                            filtered.Add(converter);

                            using (var compressed = prop.GetRawValueReadStream()) {
                                compressed.CopyTo(filtered, 4096);
                                filtered.Flush();
                            }
                        }

                        rtf.ContentObject = new ContentObject(content);
                        content.Position  = 0;

                        builder.Attachments.Add(rtf);

                        Console.WriteLine("Message Property: {0} = <compressed rtf data>", prop.PropertyTag.Id);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.BodyHtml:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var html = new TextPart("html");
                        html.ContentType.Name = "body.html";
                        html.Text             = prop.ReadValueAsString();

                        builder.Attachments.Add(html);

                        Console.WriteLine("Message Property: {0} = {1}", prop.PropertyTag.Id, html.Text);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.Body:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var plain = new TextPart("plain");
                        plain.ContentType.Name = "body.txt";
                        plain.Text             = prop.ReadValueAsString();

                        builder.Attachments.Add(plain);

                        Console.WriteLine("Message Property: {0} = {1}", prop.PropertyTag.Id, plain.Text);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType);
                    }
                    break;

                default:
                    object value;

                    try {
                        value = prop.ReadValue();
                    } catch {
                        value = null;
                    }

                    Console.WriteLine("Message Property (unhandled): {0} = {1}", prop.PropertyTag.Id, value);
                    break;
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Writes the <see cref="MimeKit.MimePart"/> to the specified output stream.
        /// </summary>
        /// <remarks>
        /// Writes the MIME part to the output stream.
        /// </remarks>
        /// <param name="options">The formatting options.</param>
        /// <param name="stream">The output stream.</param>
        /// <param name="contentOnly"><c>true</c> if only the content should be written; otherwise, <c>false</c>.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="options"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="stream"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        public override void WriteTo(FormatOptions options, Stream stream, bool contentOnly, CancellationToken cancellationToken = default(CancellationToken))
        {
            base.WriteTo(options, stream, contentOnly, cancellationToken);

            if (Content == null)
            {
                return;
            }

            var cancellable = stream as ICancellableStream;

            if (Content.Encoding != encoding)
            {
                if (encoding == ContentEncoding.UUEncode)
                {
                    var begin  = string.Format("begin 0644 {0}", FileName ?? "unknown");
                    var buffer = Encoding.UTF8.GetBytes(begin);

                    if (cancellable != null)
                    {
                        cancellable.Write(buffer, 0, buffer.Length, cancellationToken);
                        cancellable.Write(options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken);
                    }
                    else
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        stream.Write(buffer, 0, buffer.Length);
                        stream.Write(options.NewLineBytes, 0, options.NewLineBytes.Length);
                    }
                }

                // transcode the content into the desired Content-Transfer-Encoding
                using (var filtered = new FilteredStream(stream)) {
                    filtered.Add(EncoderFilter.Create(encoding));

                    if (encoding != ContentEncoding.Binary)
                    {
                        filtered.Add(options.CreateNewLineFilter(EnsureNewLine));
                    }

                    Content.DecodeTo(filtered, cancellationToken);
                    filtered.Flush(cancellationToken);
                }

                if (encoding == ContentEncoding.UUEncode)
                {
                    var buffer = Encoding.ASCII.GetBytes("end");

                    if (cancellable != null)
                    {
                        cancellable.Write(buffer, 0, buffer.Length, cancellationToken);
                        cancellable.Write(options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken);
                    }
                    else
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        stream.Write(buffer, 0, buffer.Length);
                        stream.Write(options.NewLineBytes, 0, options.NewLineBytes.Length);
                    }
                }
            }
            else if (encoding != ContentEncoding.Binary)
            {
                using (var filtered = new FilteredStream(stream)) {
                    // Note: if we are writing the top-level MimePart, make sure it ends with a new-line so that
                    // MimeMessage.WriteTo() *always* ends with a new-line.
                    filtered.Add(options.CreateNewLineFilter(EnsureNewLine));
                    Content.WriteTo(filtered, cancellationToken);
                    filtered.Flush(cancellationToken);
                }
            }
            else
            {
                Content.WriteTo(stream, cancellationToken);
            }
        }
コード例 #3
0
ファイル: YEncodingTests.cs プロジェクト: youprofit/MimeKit
        public void TestSimpleYEncMessage()
        {
            using (var file = File.OpenRead("../../TestData/yenc/simple.msg")) {
                var message = MimeMessage.Load(file);

                using (var decoded = new MemoryStream()) {
                    var ydec = new YDecoder();

                    using (var filtered = new FilteredStream(decoded)) {
                        filtered.Add(new DecoderFilter(ydec));

                        ((MimePart)message.Body).ContentObject.WriteTo(filtered);
                        filtered.Flush();
                    }

                    decoded.Position = 0;

                    Assert.AreEqual(584, decoded.Length, "The decoded size does not match.");
                    Assert.AreEqual(0xded29f4f, ydec.Checksum ^ 0xffffffff, "The decoded checksum does not match.");

                    // now re-encode it
                    using (var encoded = new MemoryStream()) {
                        var ybegin = Encoding.ASCII.GetBytes("-- \n=ybegin line=128 size=584 name=testfile.txt \n");
                        var yend   = Encoding.ASCII.GetBytes("=yend size=584 crc32=ded29f4f \n");
                        var yenc   = new YEncoder();

                        encoded.Write(ybegin, 0, ybegin.Length);

                        using (var filtered = new FilteredStream(encoded)) {
                            filtered.Add(new EncoderFilter(yenc));

                            decoded.CopyTo(filtered, 4096);
                            filtered.Flush();
                        }

                        encoded.Write(yend, 0, yend.Length);

                        Assert.AreEqual(0xded29f4f, yenc.Checksum ^ 0xffffffff, "The encoded checksum does not match.");

                        using (var original = new MemoryStream()) {
                            using (var filtered = new FilteredStream(original)) {
                                filtered.Add(new Dos2UnixFilter());

                                ((MimePart)message.Body).ContentObject.WriteTo(filtered);
                                filtered.Flush();
                            }

                            var latin1 = Encoding.GetEncoding("iso-8859-1");
                            var buf    = original.GetBuffer();

                            var expected = latin1.GetString(buf, 0, (int)original.Length);

                            buf = encoded.GetBuffer();

                            var actual = latin1.GetString(buf, 0, (int)encoded.Length);

                            Assert.AreEqual(expected, actual, "Encoded value does not match original.");
                        }
                    }
                }
            }
        }
コード例 #4
0
        public void TestImapClientGMail()
        {
            var commands = new List <ImapReplayCommand> ();

            commands.Add(new ImapReplayCommand("", "gmail.greeting.txt"));
            commands.Add(new ImapReplayCommand("A00000000 CAPABILITY\r\n", "gmail.capability.txt"));
            commands.Add(new ImapReplayCommand("A00000001 AUTHENTICATE PLAIN AHVzZXJuYW1lAHBhc3N3b3Jk\r\n", "gmail.authenticate.txt"));
            commands.Add(new ImapReplayCommand("A00000002 NAMESPACE\r\n", "gmail.namespace.txt"));
            commands.Add(new ImapReplayCommand("A00000003 LIST \"\" \"INBOX\"\r\n", "gmail.list-inbox.txt"));
            commands.Add(new ImapReplayCommand("A00000004 XLIST \"\" \"*\"\r\n", "gmail.xlist.txt"));
            commands.Add(new ImapReplayCommand("A00000005 LIST \"\" \"%\"\r\n", "gmail.list-personal.txt"));
            commands.Add(new ImapReplayCommand("A00000006 CREATE UnitTests\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000007 LIST \"\" UnitTests\r\n", "gmail.list-unittests.txt"));
            commands.Add(new ImapReplayCommand("A00000008 SELECT UnitTests (CONDSTORE)\r\n", "gmail.select-unittests.txt"));

            for (int i = 0; i < 50; i++)
            {
                using (var stream = new MemoryStream()) {
                    using (var resource = GetResourceStream(string.Format("common.message.{0}.msg", i))) {
                        using (var filtered = new FilteredStream(stream)) {
                            filtered.Add(new Unix2DosFilter());
                            resource.CopyTo(filtered, 4096);
                            filtered.Flush();
                        }

                        stream.Position = 0;
                    }

                    MimeMessage.Load(stream);

                    long   length = stream.Length;
                    string latin1;

                    stream.Position = 0;
                    using (var reader = new StreamReader(stream, Latin1))
                        latin1 = reader.ReadToEnd();

                    var command = string.Format("A{0:D8} APPEND UnitTests (\\Seen) ", i + 9);
                    command += "{" + length + "}\r\n";

                    commands.Add(new ImapReplayCommand(command, "gmail.go-ahead.txt"));
                    commands.Add(new ImapReplayCommand(latin1 + "\r\n", string.Format("gmail.append.{0}.txt", i + 1)));
                }
            }

            commands.Add(new ImapReplayCommand("A00000059 UID SEARCH RETURN () CHARSET US-ASCII OR TO nsb CC nsb\r\n", "gmail.search.txt"));
            commands.Add(new ImapReplayCommand("A00000060 UID FETCH 1:3,5,7:9,11:14,26:29,31,34,41:43,50 (UID FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)\r\n", "gmail.search-summary.txt"));
            commands.Add(new ImapReplayCommand("A00000061 UID FETCH 1 (BODY.PEEK[])\r\n", "gmail.fetch.1.txt"));
            commands.Add(new ImapReplayCommand("A00000062 UID FETCH 2 (BODY.PEEK[])\r\n", "gmail.fetch.2.txt"));
            commands.Add(new ImapReplayCommand("A00000063 UID FETCH 3 (BODY.PEEK[])\r\n", "gmail.fetch.3.txt"));
            commands.Add(new ImapReplayCommand("A00000064 UID FETCH 5 (BODY.PEEK[])\r\n", "gmail.fetch.5.txt"));
            commands.Add(new ImapReplayCommand("A00000065 UID FETCH 7 (BODY.PEEK[])\r\n", "gmail.fetch.7.txt"));
            commands.Add(new ImapReplayCommand("A00000066 UID FETCH 8 (BODY.PEEK[])\r\n", "gmail.fetch.8.txt"));
            commands.Add(new ImapReplayCommand("A00000067 UID FETCH 9 (BODY.PEEK[])\r\n", "gmail.fetch.9.txt"));
            commands.Add(new ImapReplayCommand("A00000068 UID FETCH 11 (BODY.PEEK[])\r\n", "gmail.fetch.11.txt"));
            commands.Add(new ImapReplayCommand("A00000069 UID FETCH 12 (BODY.PEEK[])\r\n", "gmail.fetch.12.txt"));
            commands.Add(new ImapReplayCommand("A00000070 UID FETCH 13 (BODY.PEEK[])\r\n", "gmail.fetch.13.txt"));
            commands.Add(new ImapReplayCommand("A00000071 UID FETCH 14 (BODY.PEEK[])\r\n", "gmail.fetch.14.txt"));
            commands.Add(new ImapReplayCommand("A00000072 UID FETCH 26 (BODY.PEEK[])\r\n", "gmail.fetch.26.txt"));
            commands.Add(new ImapReplayCommand("A00000073 UID FETCH 27 (BODY.PEEK[])\r\n", "gmail.fetch.27.txt"));
            commands.Add(new ImapReplayCommand("A00000074 UID FETCH 28 (BODY.PEEK[])\r\n", "gmail.fetch.28.txt"));
            commands.Add(new ImapReplayCommand("A00000075 UID FETCH 29 (BODY.PEEK[])\r\n", "gmail.fetch.29.txt"));
            commands.Add(new ImapReplayCommand("A00000076 UID FETCH 31 (BODY.PEEK[])\r\n", "gmail.fetch.31.txt"));
            commands.Add(new ImapReplayCommand("A00000077 UID FETCH 34 (BODY.PEEK[])\r\n", "gmail.fetch.34.txt"));
            commands.Add(new ImapReplayCommand("A00000078 UID FETCH 41 (BODY.PEEK[])\r\n", "gmail.fetch.41.txt"));
            commands.Add(new ImapReplayCommand("A00000079 UID FETCH 42 (BODY.PEEK[])\r\n", "gmail.fetch.42.txt"));
            commands.Add(new ImapReplayCommand("A00000080 UID FETCH 43 (BODY.PEEK[])\r\n", "gmail.fetch.43.txt"));
            commands.Add(new ImapReplayCommand("A00000081 UID FETCH 50 (BODY.PEEK[])\r\n", "gmail.fetch.50.txt"));
            commands.Add(new ImapReplayCommand("A00000082 UID STORE 1:3,5,7:9,11:14,26:29,31,34,41:43,50 FLAGS (\\Answered \\Seen)\r\n", "gmail.set-flags.txt"));
            commands.Add(new ImapReplayCommand("A00000083 UID STORE 1:3,5,7:9,11:14,26:29,31,34,41:43,50 -FLAGS.SILENT (\\Answered)\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000084 UID STORE 1:3,5,7:9,11:14,26:29,31,34,41:43,50 +FLAGS.SILENT (\\Deleted)\r\n", "gmail.add-flags.txt"));
            commands.Add(new ImapReplayCommand("A00000085 UNSELECT\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000086 SUBSCRIBE UnitTests\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000087 LSUB \"\" \"%\"\r\n", "gmail.lsub-personal.txt"));
            commands.Add(new ImapReplayCommand("A00000088 UNSUBSCRIBE UnitTests\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000089 CREATE UnitTests/Dummy\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000090 LIST \"\" UnitTests/Dummy\r\n", "gmail.list-unittests-dummy.txt"));
            commands.Add(new ImapReplayCommand("A00000091 RENAME UnitTests RenamedUnitTests\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000092 DELETE RenamedUnitTests\r\n", ImapReplayCommandResponse.OK));
            commands.Add(new ImapReplayCommand("A00000093 LOGOUT\r\n", "gmail.logout.txt"));

            using (var client = new ImapClient()) {
                try {
                    client.ReplayConnect("localhost", new ImapReplayStream(commands, false));
                } catch (Exception ex) {
                    Assert.Fail("Did not expect an exception in Connect: {0}", ex);
                }

                Assert.IsTrue(client.IsConnected, "Client failed to connect.");

                Assert.AreEqual(GMailInitialCapabilities, client.Capabilities);
                Assert.AreEqual(4, client.AuthenticationMechanisms.Count);
                Assert.IsTrue(client.AuthenticationMechanisms.Contains("XOAUTH"), "Expected SASL XOAUTH auth mechanism");
                Assert.IsTrue(client.AuthenticationMechanisms.Contains("XOAUTH2"), "Expected SASL XOAUTH2 auth mechanism");
                Assert.IsTrue(client.AuthenticationMechanisms.Contains("PLAIN"), "Expected SASL PLAIN auth mechanism");
                Assert.IsTrue(client.AuthenticationMechanisms.Contains("PLAIN-CLIENTTOKEN"), "Expected SASL PLAIN-CLIENTTOKEN auth mechanism");

                try {
                    var credentials = new NetworkCredential("username", "password");

                    // Note: Do not try XOAUTH2
                    client.AuthenticationMechanisms.Remove("XOAUTH2");

                    client.Authenticate(credentials);
                } catch (Exception ex) {
                    Assert.Fail("Did not expect an exception in Authenticate: {0}", ex);
                }

                Assert.AreEqual(GMailAuthenticatedCapabilities, client.Capabilities);

                var inbox = client.Inbox;
                Assert.IsNotNull(inbox, "Expected non-null Inbox folder.");
                Assert.AreEqual(FolderAttributes.Inbox | FolderAttributes.HasNoChildren, inbox.Attributes, "Expected Inbox attributes to be \\HasNoChildren.");

                foreach (var special in Enum.GetValues(typeof(SpecialFolder)).OfType <SpecialFolder> ())
                {
                    var folder = client.GetFolder(special);

                    if (special != SpecialFolder.Archive)
                    {
                        var expected = GetSpecialFolderAttribute(special) | FolderAttributes.HasNoChildren;

                        Assert.IsNotNull(folder, "Expected non-null {0} folder.", special);
                        Assert.AreEqual(expected, folder.Attributes, "Expected {0} attributes to be \\HasNoChildren.", special);
                    }
                    else
                    {
                        Assert.IsNull(folder, "Expected null {0} folder.", special);
                    }
                }

                var personal = client.GetFolder(client.PersonalNamespaces[0]);
                var folders  = personal.GetSubfolders().ToList();
                Assert.AreEqual(client.Inbox, folders[0], "Expected the first folder to be the Inbox.");
                Assert.AreEqual("[Gmail]", folders[1].FullName, "Expected the second folder to be [Gmail].");
                Assert.AreEqual(FolderAttributes.NoSelect | FolderAttributes.HasChildren, folders[1].Attributes, "Expected [Gmail] folder to be \\Noselect \\HasChildren.");

                var created = personal.Create("UnitTests", true);
                Assert.IsNotNull(created, "Expected a non-null created folder.");
                Assert.AreEqual(FolderAttributes.HasNoChildren, created.Attributes);

                Assert.IsNotNull(created.ParentFolder, "The ParentFolder property should not be null.");

                const MessageFlags ExpectedPermanentFlags = MessageFlags.Answered | MessageFlags.Flagged | MessageFlags.Draft | MessageFlags.Deleted | MessageFlags.Seen | MessageFlags.UserDefined;
                const MessageFlags ExpectedAcceptedFlags  = MessageFlags.Answered | MessageFlags.Flagged | MessageFlags.Draft | MessageFlags.Deleted | MessageFlags.Seen;
                var access = created.Open(FolderAccess.ReadWrite);
                Assert.AreEqual(FolderAccess.ReadWrite, access, "The UnitTests folder was not opened with the expected access mode.");
                Assert.AreEqual(ExpectedPermanentFlags, created.PermanentFlags, "The PermanentFlags do not match the expected value.");
                Assert.AreEqual(ExpectedAcceptedFlags, created.AcceptedFlags, "The AcceptedFlags do not match the expected value.");

                for (int i = 0; i < 50; i++)
                {
                    using (var stream = GetResourceStream(string.Format("common.message.{0}.msg", i))) {
                        var message = MimeMessage.Load(stream);

                        var uid = created.Append(message, MessageFlags.Seen);
                        Assert.IsTrue(uid.HasValue, "Expected a UID to be returned from folder.Append().");
                        Assert.AreEqual((uint)(i + 1), uid.Value.Id, "The UID returned from the APPEND command does not match the expected UID.");
                    }
                }

                var query   = SearchQuery.ToContains("nsb").Or(SearchQuery.CcContains("nsb"));
                var matches = created.Search(query);

                const MessageSummaryItems items = MessageSummaryItems.Full | MessageSummaryItems.UniqueId;
                var summaries = created.Fetch(matches, items);

                foreach (var summary in summaries)
                {
                    if (summary.UniqueId.IsValid)
                    {
                        created.GetMessage(summary.UniqueId);
                    }
                    else
                    {
                        created.GetMessage(summary.Index);
                    }
                }

                created.SetFlags(matches, MessageFlags.Seen | MessageFlags.Answered, false);
                created.RemoveFlags(matches, MessageFlags.Answered, true);
                created.AddFlags(matches, MessageFlags.Deleted, true);

                created.Close();
                Assert.IsFalse(created.IsOpen, "Expected the UnitTests folder to be closed.");

                created.Subscribe();
                Assert.IsTrue(created.IsSubscribed, "Expected IsSubscribed to be true after subscribing to the folder.");

                var subscribed = personal.GetSubfolders(true).ToList();
                Assert.IsTrue(subscribed.Contains(created), "Expected the list of subscribed folders to contain the UnitTests folder.");

                created.Unsubscribe();
                Assert.IsFalse(created.IsSubscribed, "Expected IsSubscribed to be false after unsubscribing from the folder.");

                var  dummy        = created.Create("Dummy", true);
                bool dummyRenamed = false;
                bool renamed      = false;

                dummy.Renamed   += (sender, e) => { dummyRenamed = true; };
                created.Renamed += (sender, e) => { renamed = true; };

                created.Rename(created.ParentFolder, "RenamedUnitTests");
                Assert.AreEqual("RenamedUnitTests", created.Name);
                Assert.AreEqual("RenamedUnitTests", created.FullName);
                Assert.IsTrue(renamed, "Expected the Rename event to be emitted for the UnitTests folder.");

                Assert.AreEqual("RenamedUnitTests/Dummy", dummy.FullName);
                Assert.IsTrue(dummyRenamed, "Expected the Rename event to be emitted for the UnitTests/Dummy folder.");

                created.Delete(CancellationToken.None);

                client.Disconnect(true);
            }
        }
コード例 #5
0
        async Task <bool> VerifyAsync(FormatOptions options, MimeMessage message, Header dkimSignature, bool doAsync, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (dkimSignature == null)
            {
                throw new ArgumentNullException(nameof(dkimSignature));
            }

            if (dkimSignature.Id != HeaderId.DkimSignature)
            {
                throw new ArgumentException("The signature parameter MUST be a DKIM-Signature header.", nameof(dkimSignature));
            }

            var parameters = ParseParameterTags(dkimSignature.Id, dkimSignature.Value);
            DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm;
            DkimSignatureAlgorithm        signatureAlgorithm;
            AsymmetricKeyParameter        key;
            string d, s, q, bh, b;

            string[] headers;
            int      maxLength;

            ValidateDkimSignatureParameters(parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm,
                                            out d, out s, out q, out headers, out bh, out b, out maxLength);

            if (!IsEnabled(signatureAlgorithm))
            {
                return(false);
            }

            if (doAsync)
            {
                key = await PublicKeyLocator.LocatePublicKeyAsync(q, d, s, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                key = PublicKeyLocator.LocatePublicKey(q, d, s, cancellationToken);
            }

            if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength)
            {
                return(false);
            }

            options = options.Clone();
            options.NewLineFormat = NewLineFormat.Dos;

            // first check the body hash (if that's invalid, then the entire signature is invalid)
            var hash = Convert.ToBase64String(message.HashBody(options, signatureAlgorithm, bodyAlgorithm, maxLength));

            if (hash != bh)
            {
                return(false);
            }

            using (var stream = new DkimSignatureStream(CreateVerifyContext(signatureAlgorithm, key))) {
                using (var filtered = new FilteredStream(stream)) {
                    filtered.Add(options.CreateNewLineFilter());

                    WriteHeaders(options, message, headers, headerAlgorithm, filtered);

                    // now include the DKIM-Signature header that we are verifying,
                    // but only after removing the "b=" signature value.
                    var header = GetSignedSignatureHeader(dkimSignature);

                    switch (headerAlgorithm)
                    {
                    case DkimCanonicalizationAlgorithm.Relaxed:
                        WriteHeaderRelaxed(options, filtered, header, true);
                        break;

                    default:
                        WriteHeaderSimple(options, filtered, header, true);
                        break;
                    }

                    filtered.Flush();
                }

                return(stream.VerifySignature(b));
            }
        }
コード例 #6
0
ファイル: TnefPart.cs プロジェクト: tablesmit/MimeKit
        static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder)
        {
            var prop = reader.TnefPropertyReader;

            while (prop.ReadNextProperty())
            {
                switch (prop.PropertyTag.Id)
                {
                case TnefPropertyId.InternetMessageId:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.MessageId = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.Subject:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.Subject = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.RtfCompressed:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var rtf = new TextPart("rtf");
                        rtf.ContentType.Name = "body.rtf";

                        var converter = new RtfCompressedToRtf();
                        var content   = new MemoryBlockStream();

                        using (var filtered = new FilteredStream(content)) {
                            filtered.Add(converter);

                            using (var compressed = prop.GetRawValueReadStream()) {
                                compressed.CopyTo(filtered, 4096);
                                filtered.Flush();
                            }
                        }

                        rtf.ContentObject = new ContentObject(content);
                        content.Position  = 0;

                        builder.Attachments.Add(rtf);
                    }
                    break;

                case TnefPropertyId.BodyHtml:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var html = new TextPart("html");
                        html.ContentType.Name = "body.html";
                        html.Text             = prop.ReadValueAsString();

                        builder.Attachments.Add(html);
                    }
                    break;

                case TnefPropertyId.Body:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var plain = new TextPart("plain");
                        plain.ContentType.Name = "body.txt";
                        plain.Text             = prop.ReadValueAsString();

                        builder.Attachments.Add(plain);
                    }
                    break;
                }
            }
        }
コード例 #7
0
        private async Task SendAsyncInternal(EmailMessage message, string emailType, bool enableNotification)
        {
            if (enableNotification)
            {
                var notification = new SendEmailNotification(message.ToNotificationEmail(_globalSettings.Smtp?.From), emailType);
                await _eventAggregator.PublishAsync(notification);

                // if a handler handled sending the email then don't continue.
                if (notification.IsHandled)
                {
                    _logger.LogDebug("The email sending for {Subject} was handled by a notification handler", notification.Message.Subject);
                    return;
                }
            }

            var isPickupDirectoryConfigured = !string.IsNullOrWhiteSpace(_globalSettings.Smtp?.PickupDirectoryLocation);

            if (_globalSettings.IsSmtpServerConfigured == false && !isPickupDirectoryConfigured)
            {
                _logger.LogDebug("Could not send email for {Subject}. It was not handled by a notification handler and there is no SMTP configured.", message.Subject);
                return;
            }

            if (isPickupDirectoryConfigured && !string.IsNullOrWhiteSpace(_globalSettings.Smtp?.From))
            {
                // The following code snippet is the recommended way to handle PickupDirectoryLocation.
                // See more https://github.com/jstedfast/MailKit/blob/master/FAQ.md#q-how-can-i-send-email-to-a-specifiedpickupdirectory
                do
                {
                    var    path = Path.Combine(_globalSettings.Smtp?.PickupDirectoryLocation, Guid.NewGuid() + ".eml");
                    Stream stream;

                    try
                    {
                        stream = File.Open(path, FileMode.CreateNew);
                    }
                    catch (IOException)
                    {
                        if (File.Exists(path))
                        {
                            continue;
                        }
                        throw;
                    }

                    try {
                        using (stream)
                        {
                            using var filtered = new FilteredStream(stream);
                            filtered.Add(new SmtpDataFilter());

                            FormatOptions options = FormatOptions.Default.Clone();
                            options.NewLineFormat = NewLineFormat.Dos;

                            await message.ToMimeMessage(_globalSettings.Smtp?.From).WriteToAsync(options, filtered);

                            filtered.Flush();
                            return;
                        }
                    } catch {
                        File.Delete(path);
                        throw;
                    }
                } while (true);
            }

            using var client = new SmtpClient();

            await client.ConnectAsync(_globalSettings.Smtp.Host,
                                      _globalSettings.Smtp.Port,
                                      (MailKit.Security.SecureSocketOptions)(int) _globalSettings.Smtp.SecureSocketOptions);

            if (!(_globalSettings.Smtp.Username is null && _globalSettings.Smtp.Password is null))
            {
                await client.AuthenticateAsync(_globalSettings.Smtp.Username, _globalSettings.Smtp.Password);
            }

            var mailMessage = message.ToMimeMessage(_globalSettings.Smtp.From);

            if (_globalSettings.Smtp.DeliveryMethod == SmtpDeliveryMethod.Network)
            {
                await client.SendAsync(mailMessage);
            }
            else
            {
                client.Send(mailMessage);
            }

            await client.DisconnectAsync(true);
        }
コード例 #8
0
        static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder)
        {
            var            prop              = reader.TnefPropertyReader;
            var            recipient         = new EmailAddress();
            var            sender            = new EmailAddress();
            string         normalizedSubject = null;
            string         subjectPrefix     = null;
            MailboxAddress mailbox;
            var            msgid = false;

            while (prop.ReadNextProperty())
            {
                switch (prop.PropertyTag.Id)
                {
                case TnefPropertyId.InternetMessageId:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.MessageId = prop.ReadValueAsString();
                        msgid             = true;
                    }
                    break;

                case TnefPropertyId.TnefCorrelationKey:
                    // According to MSDN, PidTagTnefCorrelationKey is a unique key that is
                    // meant to be used to tie the TNEF attachment to the encapsulating
                    // message. It can be a string or a binary blob. It seems that most
                    // implementations use the Message-Id string, so if this property
                    // value looks like a Message-Id, then us it as one (unless we get a
                    // InternetMessageId property, in which case we use that instead.
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        if (!msgid)
                        {
                            var value = prop.ReadValueAsString();

                            if (value.Length > 5 && value[0] == '<' && value[value.Length - 1] == '>' && value.IndexOf('@') != -1)
                            {
                                message.MessageId = value;
                            }
                        }
                    }
                    break;

                case TnefPropertyId.Subject:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.Subject = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.SubjectPrefix:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        subjectPrefix = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.NormalizedSubject:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        normalizedSubject = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.SenderName:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        sender.Name = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.SenderEmailAddress:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        sender.Addr = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.SenderSearchKey:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        sender.SearchKey = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.SenderAddrtype:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        sender.AddrType = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.ReceivedByName:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        recipient.Name = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.ReceivedByEmailAddress:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        recipient.Addr = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.ReceivedBySearchKey:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        recipient.SearchKey = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.ReceivedByAddrtype:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        recipient.AddrType = prop.ReadValueAsString();
                    }
                    break;

                case TnefPropertyId.RtfCompressed:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var rtf = new TextPart("rtf");

                        var converter = new RtfCompressedToRtf();
                        var content   = new MemoryBlockStream();

                        using (var filtered = new FilteredStream(content)) {
                            filtered.Add(converter);

                            using (var compressed = prop.GetRawValueReadStream()) {
                                compressed.CopyTo(filtered, 4096);
                                filtered.Flush();
                            }
                        }

                        rtf.Content      = new MimeContent(content);
                        content.Position = 0;

                        builder.Attachments.Add(rtf);
                    }
                    break;

                case TnefPropertyId.BodyHtml:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var      html = new TextPart("html");
                        Encoding encoding;

                        if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode)
                        {
                            encoding = Encoding.GetEncoding(reader.MessageCodepage);
                        }
                        else
                        {
                            encoding = CharsetUtils.UTF8;
                        }

                        html.SetText(encoding, prop.ReadValueAsString());

                        builder.Attachments.Add(html);
                    }
                    break;

                case TnefPropertyId.Body:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var      plain = new TextPart("plain");
                        Encoding encoding;

                        if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode)
                        {
                            encoding = Encoding.GetEncoding(reader.MessageCodepage);
                        }
                        else
                        {
                            encoding = CharsetUtils.UTF8;
                        }

                        plain.SetText(encoding, prop.ReadValueAsString());

                        builder.Attachments.Add(plain);
                    }
                    break;

                case TnefPropertyId.Importance:
                    // https://msdn.microsoft.com/en-us/library/ee237166(v=exchg.80).aspx
                    switch (prop.ReadValueAsInt32())
                    {
                    case 2: message.Importance = MessageImportance.High; break;

                    case 1: message.Importance = MessageImportance.Normal; break;

                    case 0: message.Importance = MessageImportance.Low; break;
                    }
                    break;

                case TnefPropertyId.Priority:
                    // https://msdn.microsoft.com/en-us/library/ee159473(v=exchg.80).aspx
                    switch (prop.ReadValueAsInt32())
                    {
                    case  1: message.Priority = MessagePriority.Urgent; break;

                    case  0: message.Priority = MessagePriority.Normal; break;

                    case -1: message.Priority = MessagePriority.NonUrgent; break;
                    }
                    break;

                case TnefPropertyId.Sensitivity:
                    // https://msdn.microsoft.com/en-us/library/ee217353(v=exchg.80).aspx
                    // https://tools.ietf.org/html/rfc2156#section-5.3.4
                    switch (prop.ReadValueAsInt32())
                    {
                    case 1: message.Headers[HeaderId.Sensitivity] = "Personal"; break;

                    case 2: message.Headers[HeaderId.Sensitivity] = "Private"; break;

                    case 3: message.Headers[HeaderId.Sensitivity] = "Company-Confidential"; break;

                    case 0: message.Headers.Remove(HeaderId.Sensitivity); break;
                    }
                    break;
                }
            }

            if (string.IsNullOrEmpty(message.Subject) && !string.IsNullOrEmpty(normalizedSubject))
            {
                if (!string.IsNullOrEmpty(subjectPrefix))
                {
                    message.Subject = subjectPrefix + normalizedSubject;
                }
                else
                {
                    message.Subject = normalizedSubject;
                }
            }

            if (sender.TryGetMailboxAddress(out mailbox))
            {
                message.From.Add(mailbox);
            }

            if (recipient.TryGetMailboxAddress(out mailbox))
            {
                message.To.Add(mailbox);
            }
        }
コード例 #9
0
        static void ExtractAttachments(TnefReader reader, BodyBuilder builder)
        {
            var             attachMethod = TnefAttachMethod.ByValue;
            var             filter = new BestEncodingFilter();
            var             prop = reader.TnefPropertyReader;
            MimePart        attachment = null;
            int             outIndex, outLength;
            TnefAttachFlags flags;

            string[] mimeType;
            byte[]   attachData;
            string   text;

            do
            {
                if (reader.AttributeLevel != TnefAttributeLevel.Attachment)
                {
                    break;
                }

                switch (reader.AttributeTag)
                {
                case TnefAttributeTag.AttachRenderData:
                    attachMethod = TnefAttachMethod.ByValue;
                    attachment   = new MimePart();
                    break;

                case TnefAttributeTag.Attachment:
                    if (attachment == null)
                    {
                        break;
                    }

                    while (prop.ReadNextProperty())
                    {
                        switch (prop.PropertyTag.Id)
                        {
                        case TnefPropertyId.AttachLongFilename:
                            attachment.FileName = prop.ReadValueAsString();
                            break;

                        case TnefPropertyId.AttachFilename:
                            if (attachment.FileName == null)
                            {
                                attachment.FileName = prop.ReadValueAsString();
                            }
                            break;

                        case TnefPropertyId.AttachContentLocation:
                            attachment.ContentLocation = prop.ReadValueAsUri();
                            break;

                        case TnefPropertyId.AttachContentBase:
                            attachment.ContentBase = prop.ReadValueAsUri();
                            break;

                        case TnefPropertyId.AttachContentId:
                            attachment.ContentId = prop.ReadValueAsString();
                            break;

                        case TnefPropertyId.AttachDisposition:
                            text = prop.ReadValueAsString();
                            if (attachment.ContentDisposition == null)
                            {
                                attachment.ContentDisposition = new ContentDisposition(text);
                            }
                            else
                            {
                                attachment.ContentDisposition.Disposition = text;
                            }
                            break;

                        case TnefPropertyId.AttachData:
                            var stream  = prop.GetRawValueReadStream();
                            var content = new MemoryStream();

                            if (attachMethod == TnefAttachMethod.EmbeddedMessage)
                            {
                                var tnef = new TnefPart();

                                foreach (var param in attachment.ContentType.Parameters)
                                {
                                    tnef.ContentType.Parameters[param.Name] = param.Value;
                                }

                                if (attachment.ContentDisposition != null)
                                {
                                    tnef.ContentDisposition = attachment.ContentDisposition;
                                }

                                attachment = tnef;
                            }

                            // the rest is content
                            using (var filtered = new FilteredStream(content)) {
                                filtered.Add(filter);
                                stream.CopyTo(filtered, 4096);
                                filtered.Flush();
                            }

                            content.Position = 0;

                            attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.SevenBit);
                            attachment.Content = new MimeContent(content);
                            filter.Reset();

                            builder.Attachments.Add(attachment);
                            break;

                        case TnefPropertyId.AttachMethod:
                            attachMethod = (TnefAttachMethod)prop.ReadValueAsInt32();
                            break;

                        case TnefPropertyId.AttachMimeTag:
                            mimeType = prop.ReadValueAsString().Split('/');
                            if (mimeType.Length == 2)
                            {
                                attachment.ContentType.MediaType    = mimeType[0].Trim();
                                attachment.ContentType.MediaSubtype = mimeType[1].Trim();
                            }
                            break;

                        case TnefPropertyId.AttachFlags:
                            flags = (TnefAttachFlags)prop.ReadValueAsInt32();
                            if ((flags & TnefAttachFlags.RenderedInBody) != 0)
                            {
                                if (attachment.ContentDisposition == null)
                                {
                                    attachment.ContentDisposition = new ContentDisposition(ContentDisposition.Inline);
                                }
                                else
                                {
                                    attachment.ContentDisposition.Disposition = ContentDisposition.Inline;
                                }
                            }
                            break;

                        case TnefPropertyId.AttachSize:
                            if (attachment.ContentDisposition == null)
                            {
                                attachment.ContentDisposition = new ContentDisposition();
                            }

                            attachment.ContentDisposition.Size = prop.ReadValueAsInt64();
                            break;

                        case TnefPropertyId.DisplayName:
                            attachment.ContentType.Name = prop.ReadValueAsString();
                            break;
                        }
                    }
                    break;

                case TnefAttributeTag.AttachCreateDate:
                    if (attachment != null)
                    {
                        if (attachment.ContentDisposition == null)
                        {
                            attachment.ContentDisposition = new ContentDisposition();
                        }

                        attachment.ContentDisposition.CreationDate = prop.ReadValueAsDateTime();
                    }
                    break;

                case TnefAttributeTag.AttachModifyDate:
                    if (attachment != null)
                    {
                        if (attachment.ContentDisposition == null)
                        {
                            attachment.ContentDisposition = new ContentDisposition();
                        }

                        attachment.ContentDisposition.ModificationDate = prop.ReadValueAsDateTime();
                    }
                    break;

                case TnefAttributeTag.AttachTitle:
                    if (attachment != null && string.IsNullOrEmpty(attachment.FileName))
                    {
                        attachment.FileName = prop.ReadValueAsString();
                    }
                    break;

                case TnefAttributeTag.AttachMetaFile:
                    if (attachment == null)
                    {
                        break;
                    }

                    // TODO: what to do with the meta data?
                    break;

                case TnefAttributeTag.AttachData:
                    if (attachment == null || attachMethod != TnefAttachMethod.ByValue)
                    {
                        break;
                    }

                    attachData = prop.ReadValueAsBytes();
                    filter.Flush(attachData, 0, attachData.Length, out outIndex, out outLength);
                    attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.EightBit);
                    attachment.Content = new MimeContent(new MemoryStream(attachData, false));
                    filter.Reset();

                    builder.Attachments.Add(attachment);
                    break;
                }
            } while (reader.ReadNextAttribute());
        }
コード例 #10
0
        public void TestCharsetFilter()
        {
            const string  french = "Wikipédia est un projet d’encyclopédie collective en ligne, universelle, multilingue et fonctionnant sur le principe du wiki. Wikipédia a pour objectif d’offrir un contenu librement réutilisable, objectif et vérifiable, que chacun peut modifier et améliorer.\n\nTous les rédacteurs des articles de Wikipédia sont bénévoles. Ils coordonnent leurs efforts au sein d'une communauté collaborative, sans dirigeant.";
            CharsetFilter filter;

            Assert.Throws <ArgumentNullException> (() => new CharsetFilter(null, "iso-8859-1"));
            Assert.Throws <ArgumentNullException> (() => new CharsetFilter("iso-8859-1", null));
            Assert.Throws <NotSupportedException> (() => new CharsetFilter("bogus charset", "iso-8859-1"));
            Assert.Throws <NotSupportedException> (() => new CharsetFilter("iso-8859-1", "bogus charset"));

            Assert.Throws <ArgumentNullException> (() => new CharsetFilter(null, Encoding.UTF8));
            Assert.Throws <ArgumentNullException> (() => new CharsetFilter(Encoding.UTF8, null));

            Assert.Throws <ArgumentOutOfRangeException> (() => new CharsetFilter(-1, 28591));
            Assert.Throws <ArgumentOutOfRangeException> (() => new CharsetFilter(28591, -1));

            filter = new CharsetFilter(Encoding.UTF8, CharsetUtils.Latin1);

            TestArgumentExceptions(filter);
            filter.Reset();

            // Try converting, no fallback
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(french))) {
                using (var filtered = new FilteredStream(stream)) {
                    var expected = Encoding.GetEncoding("iso-8859-15").GetBytes(french);
                    var buffer   = new byte[1024];
                    int length;

                    filtered.Add(new CharsetFilter("utf-8", "iso-8859-15"));

                    length  = filtered.Read(buffer, 0, expected.Length / 2);
                    length += filtered.Read(buffer, expected.Length / 2, buffer.Length - (expected.Length / 2));

                    // Note: this Flush() should do nothing but test a code-path
                    filtered.Flush();

                    Assert.AreEqual(expected.Length, length, "iso-8859-15 length");
                }
            }

            // Try converting with fallback (at least 1 char does not fit within iso-8859-1)
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(french))) {
                using (var filtered = new FilteredStream(stream)) {
                    var utf8     = Encoding.GetEncoding("utf-8", new EncoderReplacementFallback("?"), new DecoderReplacementFallback("?"));
                    var latin1   = Encoding.GetEncoding("iso-8859-1", new EncoderReplacementFallback("?"), new DecoderReplacementFallback("?"));
                    var expected = latin1.GetBytes(french);
                    var buffer   = new byte[1024];
                    int length;

                    filtered.Add(new CharsetFilter(utf8, latin1));

                    length  = filtered.Read(buffer, 0, expected.Length / 2);
                    length += filtered.Read(buffer, expected.Length / 2, buffer.Length - (expected.Length / 2));

                    // Note: this Flush() should do nothing but test a code-path
                    filtered.Flush();

                    Assert.AreEqual(expected.Length, length, "iso-8859-1 length");
                }
            }
        }
コード例 #11
0
        public void TestBestEncodingFilter()
        {
            const string fromLines = "This text is meant to test that the filter will armor lines beginning with\nFrom (like mbox).\n";
            const string ascii     = "This is some ascii text to make sure that\nthe filter returns 7bit encoding...\n";
            const string french    = "Wikipédia est un projet d’encyclopédie collective en ligne, universelle, multilingue et fonctionnant sur le principe du wiki. Wikipédia a pour objectif d’offrir un contenu librement réutilisable, objectif et vérifiable, que chacun peut modifier et améliorer.\n\nTous les rédacteurs des articles de Wikipédia sont bénévoles. Ils coordonnent leurs efforts au sein d'une communauté collaborative, sans dirigeant.";
            var          filter    = new BestEncodingFilter();

            TestArgumentExceptions(filter);

            Assert.Throws <ArgumentOutOfRangeException> (() => filter.GetBestEncoding(EncodingConstraint.SevenBit, 10));

            // Test ASCII text
            using (var stream = new MemoryStream()) {
                using (var filtered = new FilteredStream(stream)) {
                    var             buffer = Encoding.UTF8.GetBytes(ascii);
                    ContentEncoding encoding;

                    Assert.IsFalse(filtered.CanTimeout, "CanTimeout");
                    Assert.Throws <InvalidOperationException> (() => { var x = filtered.ReadTimeout; });
                    Assert.Throws <InvalidOperationException> (() => { var x = filtered.WriteTimeout; });
                    Assert.Throws <InvalidOperationException> (() => filtered.ReadTimeout  = 50);
                    Assert.Throws <InvalidOperationException> (() => filtered.WriteTimeout = 50);
                    Assert.Throws <NotSupportedException> (() => { long x = filtered.Length; });
                    Assert.Throws <NotSupportedException> (() => filtered.SetLength(100));
                    Assert.Throws <NotSupportedException> (() => { long x = filtered.Position; });
                    Assert.Throws <NotSupportedException> (() => filtered.Position = 0);

                    Assert.Throws <ArgumentNullException> (() => filtered.Add(null));
                    Assert.Throws <ArgumentNullException> (() => filtered.Contains(null));
                    Assert.Throws <ArgumentNullException> (() => filtered.Remove(null));

                    filtered.Add(filter);

                    Assert.IsTrue(filtered.Contains(filter), "Contains");

                    filtered.Write(buffer, 0, buffer.Length);
                    filtered.Flush();

                    encoding = filter.GetBestEncoding(EncodingConstraint.SevenBit);
                    Assert.AreEqual(ContentEncoding.SevenBit, encoding, "ASCII 7bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.EightBit);
                    Assert.AreEqual(ContentEncoding.SevenBit, encoding, "ASCII 8bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.None);
                    Assert.AreEqual(ContentEncoding.SevenBit, encoding, "ASCII no constraint.");

                    Assert.IsTrue(filtered.Remove(filter), "Remove");
                }
            }

            filter.Reset();

            // Test ASCII text with a line beginning with "From "
            using (var stream = new MemoryStream()) {
                using (var filtered = new FilteredStream(stream)) {
                    int             fromIndex = fromLines.IndexOf("\nFrom ", StringComparison.Ordinal);
                    var             buffer    = Encoding.UTF8.GetBytes(fromLines);
                    ContentEncoding encoding;

                    filtered.Add(filter);

                    // write out a buffer where the end boundary falls in the middle of "From "
                    int endIndex = fromIndex + 3;
                    filtered.Write(buffer, 0, endIndex);

                    // write out the rest
                    filtered.Write(buffer, endIndex, buffer.Length - endIndex);
                    filtered.Flush();

                    encoding = filter.GetBestEncoding(EncodingConstraint.SevenBit);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "From-line 7bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.EightBit);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "From-line 8bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.None);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "From-line no constraint.");
                }
            }

            filter.Reset();

            // Test some French Latin1 text
            using (var stream = new MemoryStream()) {
                using (var filtered = new FilteredStream(stream)) {
                    var             buffer = Encoding.UTF8.GetBytes(french);
                    ContentEncoding encoding;

                    filtered.Add(filter);

                    // We'll write only 60 chars at first to not exceed the 78 char max
                    filtered.Write(buffer, 0, 60);
                    filtered.Flush();

                    encoding = filter.GetBestEncoding(EncodingConstraint.SevenBit);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "French 7bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.EightBit);
                    Assert.AreEqual(ContentEncoding.EightBit, encoding, "French 8bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.None);
                    Assert.AreEqual(ContentEncoding.EightBit, encoding, "French no constraint.");

                    filter.Reset();

                    // write the entire French text this time (longest line exceeds 78 chars)
                    filtered.Write(buffer, 0, buffer.Length);
                    filtered.Flush();

                    encoding = filter.GetBestEncoding(EncodingConstraint.SevenBit);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "French (long lines) 7bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.EightBit);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "French (long lines) 8bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.None);
                    Assert.AreEqual(ContentEncoding.QuotedPrintable, encoding, "French (long lines) no constraint.");
                }
            }

            filter.Reset();

            // Test 78 character line length with CRLF
            using (var stream = new MemoryStream()) {
                using (var filtered = new FilteredStream(stream)) {
                    var             buffer = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\r\nabc\r\n");
                    ContentEncoding encoding;

                    filtered.Add(filter);

                    filtered.Write(buffer, 0, buffer.Length);
                    filtered.Flush();

                    encoding = filter.GetBestEncoding(EncodingConstraint.SevenBit, 78);
                    Assert.AreEqual(ContentEncoding.SevenBit, encoding, "78-character line; 7bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.EightBit, 78);
                    Assert.AreEqual(ContentEncoding.SevenBit, encoding, "78-character line; 8bit constraint.");

                    encoding = filter.GetBestEncoding(EncodingConstraint.None, 78);
                    Assert.AreEqual(ContentEncoding.SevenBit, encoding, "78-character line; no constraint.");
                }
            }
        }
コード例 #12
0
        public void TestJwzMbox()
        {
            var summary = File.ReadAllText(Path.Combine(MboxDataDir, "jwz-summary.txt")).Replace("\r\n", "\n");
            var options = FormatOptions.Default.Clone();
            var original = new MemoryBlockStream();
            var output = new MemoryBlockStream();
            var builder = new StringBuilder();
            var expected = new byte[4096];
            var buffer = new byte[4096];
            int nx, n;

            options.NewLineFormat = NewLineFormat.Unix;

            using (var stream = File.OpenRead(Path.Combine(MboxDataDir, "jwz.mbox.txt"))) {
                var parser = new MimeParser(stream, MimeFormat.Mbox);
                int count  = 0;

                while (!parser.IsEndOfStream)
                {
                    var message = parser.ParseMessage();

                    builder.AppendFormat("{0}", parser.MboxMarker).Append('\n');
                    if (message.From.Count > 0)
                    {
                        builder.AppendFormat("From: {0}", message.From).Append('\n');
                    }
                    if (message.To.Count > 0)
                    {
                        builder.AppendFormat("To: {0}", message.To).Append('\n');
                    }
                    builder.AppendFormat("Subject: {0}", message.Subject).Append('\n');
                    builder.AppendFormat("Date: {0}", DateUtils.FormatDate(message.Date)).Append('\n');
                    DumpMimeTree(builder, message);
                    builder.Append('\n');

                    var marker = Encoding.UTF8.GetBytes((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n");
                    output.Write(marker, 0, marker.Length);
                    message.WriteTo(options, output);
                    count++;
                }
            }

            string actual = builder.ToString();

            // WORKAROUND: Mono's iso-2022-jp decoder breaks on this input in versions <= 3.2.3 but is fixed in 3.2.4+
            string iso2022jp = Encoding.GetEncoding("iso-2022-jp").GetString(Convert.FromBase64String("GyRAOjRGI0stGyhK"));

            if (iso2022jp != "佐藤豊")
            {
                actual = actual.Replace(iso2022jp, "佐藤豊");
            }

            Assert.AreEqual(summary, actual, "Summaries do not match for jwz.mbox");

            using (var stream = File.OpenRead(Path.Combine(MboxDataDir, "jwz.mbox.txt"))) {
                using (var filtered = new FilteredStream(original)) {
                    filtered.Add(new Dos2UnixFilter());
                    stream.CopyTo(filtered);
                    filtered.Flush();
                }
            }

            original.Position = 0;
            output.Position   = 0;

            Assert.AreEqual(original.Length, output.Length, "The length of the mbox did not match.");

            do
            {
                var position = original.Position;

                nx = original.Read(expected, 0, expected.Length);
                n  = output.Read(buffer, 0, buffer.Length);

                if (nx == 0)
                {
                    break;
                }

                for (int i = 0; i < nx; i++)
                {
                    if (buffer[i] == expected[i])
                    {
                        continue;
                    }

                    var strExpected = CharsetUtils.Latin1.GetString(expected, 0, nx);
                    var strActual   = CharsetUtils.Latin1.GetString(buffer, 0, n);

                    Assert.AreEqual(strExpected, strActual, "The mbox differs at position {0}", position + i);
                }
            } while (true);
        }
コード例 #13
0
        public virtual async Task SaveAsync(string pickupDirectory, MailMessage message)
        {
            Guard.NotEmpty(pickupDirectory, nameof(pickupDirectory));
            Guard.NotNull(message, nameof(message));

            var mimeMessage = BuildMimeMessage(message);

            do
            {
                // Generate a random file name to save the message to.
                var    path = Path.Combine(pickupDirectory, Guid.NewGuid().ToString() + ".eml");
                Stream stream;

                try
                {
                    // Attempt to create the new file.
                    stream = File.Open(path, FileMode.CreateNew);
                }
                catch (IOException)
                {
                    // If the file already exists, try again with a new Guid.
                    if (File.Exists(path))
                    {
                        continue;
                    }

                    // Otherwise, fail immediately since it probably means that there is
                    // no graceful way to recover from this error.
                    throw;
                }

                try
                {
                    using (stream)
                    {
                        // IIS pickup directories expect the message to be "byte-stuffed"
                        // which means that lines beginning with "." need to be escaped
                        // by adding an extra "." to the beginning of the line.
                        //
                        // Use an SmtpDataFilter "byte-stuff" the message as it is written
                        // to the file stream. This is the same process that an SmtpClient
                        // would use when sending the message in a `DATA` command.
                        using (var filtered = new FilteredStream(stream))
                        {
                            filtered.Add(new SmtpDataFilter());

                            // Make sure to write the message in DOS (<CR><LF>) format.
                            var options = FormatOptions.Default.Clone();
                            options.NewLineFormat = NewLineFormat.Dos;

                            await mimeMessage.WriteToAsync(options, filtered);

                            await filtered.FlushAsync();

                            return;
                        }
                    }
                }
                catch
                {
                    // An exception here probably means that the disk is full.
                    //
                    // Delete the file that was created above so that incomplete files are not
                    // left behind for IIS to send accidentally.
                    File.Delete(path);
                    throw;
                }
            } while (true);
        }
コード例 #14
0
ファイル: MimeParserTests.cs プロジェクト: xuan2261/MimeKit
        static void AssertMboxResults(string baseName, string actual, Stream output)
        {
            // WORKAROUND: Mono's iso-2022-jp decoder breaks on this input in versions <= 3.2.3 but is fixed in 3.2.4+
            string iso2022jp = Encoding.GetEncoding("iso-2022-jp").GetString(Convert.FromBase64String("GyRAOjRGI0stGyhK"));

            if (iso2022jp != "佐藤豊")
            {
                actual = actual.Replace(iso2022jp, "佐藤豊");
            }

            var path = Path.Combine(MboxDataDir, baseName + "-summary.txt");

            if (!File.Exists(path))
            {
                File.WriteAllText(path, actual);
            }

            var summary = File.ReadAllText(path).Replace("\r\n", "\n");
            var original = new MemoryBlockStream();
            var expected = new byte[4096];
            var buffer = new byte[4096];
            int nx, n;

            Assert.AreEqual(summary, actual, "Summaries do not match for {0}.mbox", baseName);

            using (var stream = File.OpenRead(Path.Combine(MboxDataDir, baseName + ".mbox.txt"))) {
                using (var filtered = new FilteredStream(original)) {
                    filtered.Add(new Dos2UnixFilter());
                    stream.CopyTo(filtered);
                    filtered.Flush();
                }
            }

            original.Position = 0;
            output.Position   = 0;

            Assert.AreEqual(original.Length, output.Length, "The length of the mbox did not match.");

            do
            {
                var position = original.Position;

                nx = original.Read(expected, 0, expected.Length);
                n  = output.Read(buffer, 0, buffer.Length);

                if (nx == 0)
                {
                    break;
                }

                for (int i = 0; i < nx; i++)
                {
                    if (buffer[i] == expected[i])
                    {
                        continue;
                    }

                    var strExpected = CharsetUtils.Latin1.GetString(expected, 0, nx);
                    var strActual   = CharsetUtils.Latin1.GetString(buffer, 0, n);

                    Assert.AreEqual(strExpected, strActual, "The mbox differs at position {0}", position + i);
                }
            } while (true);
        }
コード例 #15
0
ファイル: DkimSigner.cs プロジェクト: zhengbingjie520/MimeKit
        void DkimSign(FormatOptions options, MimeMessage message, IList <string> headers)
        {
            var value = new StringBuilder("v=1");
            var t     = GetTimestamp();

            byte[] signature, hash;
            Header dkim;

            options = options.Clone();
            options.NewLineFormat = NewLineFormat.Dos;

            switch (SignatureAlgorithm)
            {
            case DkimSignatureAlgorithm.Ed25519Sha256:
                value.Append("; a=ed25519-sha256");
                break;

            case DkimSignatureAlgorithm.RsaSha256:
                value.Append("; a=rsa-sha256");
                break;

            default:
                value.Append("; a=rsa-sha1");
                break;
            }

            value.AppendFormat("; d={0}; s={1}", Domain, Selector);
            value.AppendFormat("; c={0}/{1}",
                               HeaderCanonicalizationAlgorithm.ToString().ToLowerInvariant(),
                               BodyCanonicalizationAlgorithm.ToString().ToLowerInvariant());
            if (!string.IsNullOrEmpty(QueryMethod))
            {
                value.AppendFormat("; q={0}", QueryMethod);
            }
            if (!string.IsNullOrEmpty(AgentOrUserIdentifier))
            {
                value.AppendFormat("; i={0}", AgentOrUserIdentifier);
            }
            value.AppendFormat("; t={0}", t);

            using (var stream = new DkimSignatureStream(CreateSigningContext())) {
                using (var filtered = new FilteredStream(stream)) {
                    filtered.Add(options.CreateNewLineFilter());

                    // write the specified message headers
                    DkimVerifierBase.WriteHeaders(options, message, headers, HeaderCanonicalizationAlgorithm, filtered);

                    value.AppendFormat("; h={0}", string.Join(":", headers.ToArray()));

                    hash = message.HashBody(options, SignatureAlgorithm, BodyCanonicalizationAlgorithm, -1);
                    value.AppendFormat("; bh={0}", Convert.ToBase64String(hash));
                    value.Append("; b=");

                    dkim = new Header(HeaderId.DkimSignature, value.ToString());
                    message.Headers.Insert(0, dkim);

                    switch (HeaderCanonicalizationAlgorithm)
                    {
                    case DkimCanonicalizationAlgorithm.Relaxed:
                        DkimVerifierBase.WriteHeaderRelaxed(options, filtered, dkim, true);
                        break;

                    default:
                        DkimVerifierBase.WriteHeaderSimple(options, filtered, dkim, true);
                        break;
                    }

                    filtered.Flush();
                }

                signature = stream.GenerateSignature();

                dkim.Value += Convert.ToBase64String(signature);
            }
        }
コード例 #16
0
        static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder)
        {
            string normalizedSubject = null, subjectPrefix = null;
            var    prop = reader.TnefPropertyReader;
            var    chars = new char[1024];
            var    buf  = new byte[1024];

            while (prop.ReadNextProperty())
            {
                var    type = prop.ValueType;
                object value;

                switch (prop.PropertyTag.Id)
                {
                case TnefPropertyId.InternetMessageId:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.MessageId = prop.ReadValueAsString();
                        //Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, message.MessageId);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for Message-Id: {0}", prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.Subject:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode)
                    {
                        message.Subject = prop.ReadValueAsString();
                        //Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, message.Subject);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for Subject: {0}", prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.RtfCompressed:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var rtf = new TextPart("rtf");
                        rtf.ContentType.Name = "body.rtf";

                        var converter = new RtfCompressedToRtf();
                        converter.Reset();

                        var content = new MemoryStream();

                        using (var filtered = new FilteredStream(content)) {
                            filtered.Add(converter);

                            using (var compressed = prop.GetRawValueReadStream()) {
                                compressed.CopyTo(filtered, 4096);
                                filtered.Flush();
                            }
                        }

                        rtf.Content      = new MimeContent(content);
                        content.Position = 0;

                        builder.Attachments.Add(rtf);

                        //Console.WriteLine ("Message Property: {0} = <compressed rtf data>", prop.PropertyTag.Id);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.BodyHtml:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var html = new TextPart("html");
                        html.ContentType.Name = "body.html";
                        html.Text             = prop.ReadValueAsString();

                        builder.Attachments.Add(html);

                        //Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, html.Text);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.Body:
                    if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode ||
                        prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary)
                    {
                        var plain = new TextPart("plain");
                        plain.ContentType.Name = "body.txt";
                        plain.Text             = prop.ReadValueAsString();

                        builder.Attachments.Add(plain);

                        //Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, plain.Text);
                    }
                    else
                    {
                        Assert.Fail("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType);
                    }
                    break;

                case TnefPropertyId.AlternateRecipientAllowed:
                    Assert.AreEqual(typeof(bool), type);
                    value = prop.ReadValueAsBoolean();
                    break;

                case TnefPropertyId.MessageClass:
                    Assert.AreEqual(typeof(string), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.Importance:
                    Assert.AreEqual(typeof(int), type);
                    value = prop.ReadValueAsInt16();
                    break;

                case TnefPropertyId.Priority:
                    Assert.AreEqual(typeof(int), type);
                    value = prop.ReadValueAsInt16();
                    break;

                case TnefPropertyId.Sensitivity:
                    Assert.AreEqual(typeof(int), type);
                    value = prop.ReadValueAsInt16();
                    break;

                case TnefPropertyId.ClientSubmitTime:
                    Assert.AreEqual(typeof(DateTime), type);
                    value = prop.ReadValueAsDateTime();
                    break;

                case TnefPropertyId.SubjectPrefix:
                    Assert.AreEqual(typeof(string), type);
                    subjectPrefix = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.MessageSubmissionId:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.ConversationTopic:
                    Assert.AreEqual(typeof(string), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.ConversationIndex:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsBytes();
                    break;

                case TnefPropertyId.SenderName:
                    Assert.AreEqual(typeof(string), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.SenderEmailAddress:
                    Assert.AreEqual(typeof(string), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.SenderAddrtype:
                    Assert.AreEqual(typeof(string), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.SenderSearchKey:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.NormalizedSubject:
                    Assert.AreEqual(typeof(string), type);
                    normalizedSubject = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.CreationTime:
                    Assert.AreEqual(typeof(DateTime), type);
                    value = prop.ReadValueAsDateTime();
                    break;

                case TnefPropertyId.LastModificationTime:
                    Assert.AreEqual(typeof(DateTime), type);
                    value = prop.ReadValueAsDateTime();
                    break;

                case TnefPropertyId.InternetCPID:
                    Assert.AreEqual(typeof(int), type);
                    value = prop.ReadValueAsInt32();
                    break;

                case TnefPropertyId.MessageCodepage:
                    Assert.AreEqual(typeof(int), type);
                    value = prop.ReadValueAsInt32();
                    break;

                case TnefPropertyId.INetMailOverrideFormat:
                    Assert.AreEqual(typeof(int), type);
                    value = prop.ReadValueAsInt32();
                    break;

                case TnefPropertyId.ReadReceiptRequested:
                    Assert.AreEqual(typeof(bool), type);
                    value = prop.ReadValueAsBoolean();
                    break;

                case TnefPropertyId.OriginatorDeliveryReportRequested:
                    Assert.AreEqual(typeof(bool), type);
                    value = prop.ReadValueAsBoolean();
                    break;

                case TnefPropertyId.TnefCorrelationKey:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.DeleteAfterSubmit:
                    Assert.AreEqual(typeof(bool), type);
                    value = prop.ReadValueAsBoolean();
                    break;

                case TnefPropertyId.MessageDeliveryTime:
                    Assert.AreEqual(typeof(DateTime), type);
                    value = prop.ReadValueAsDateTime();
                    break;

                case TnefPropertyId.SentmailEntryId:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsString();
                    break;

                case TnefPropertyId.RtfInSync:
                    Assert.AreEqual(typeof(bool), type);
                    value = prop.ReadValueAsBoolean();
                    break;

                case TnefPropertyId.MappingSignature:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsBytes();
                    break;

                case TnefPropertyId.StoreRecordKey:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsBytes();
                    break;

                case TnefPropertyId.StoreEntryId:
                    Assert.AreEqual(typeof(byte[]), type);
                    value = prop.ReadValueAsBytes();
                    break;

                default:
                    Assert.Throws <ArgumentNullException> (() => prop.ReadTextValue(null, 0, chars.Length));
                    Assert.Throws <ArgumentOutOfRangeException> (() => prop.ReadTextValue(chars, -1, chars.Length));
                    Assert.Throws <ArgumentOutOfRangeException> (() => prop.ReadTextValue(chars, 0, -1));

                    Assert.Throws <ArgumentNullException> (() => prop.ReadRawValue(null, 0, buf.Length));
                    Assert.Throws <ArgumentOutOfRangeException> (() => prop.ReadRawValue(buf, -1, buf.Length));
                    Assert.Throws <ArgumentOutOfRangeException> (() => prop.ReadRawValue(buf, 0, -1));

                    if (type == typeof(int) || type == typeof(long) || type == typeof(bool) || type == typeof(double) || type == typeof(float))
                    {
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsString());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsGuid());
                    }
                    else if (type == typeof(string))
                    {
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsBoolean());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsDouble());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsFloat());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsInt16());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsInt32());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsInt64());
                        Assert.Throws <InvalidOperationException> (() => prop.ReadValueAsGuid());
                    }

                    try {
                        value = prop.ReadValue();
                    } catch (Exception ex) {
                        Console.WriteLine("Error in prop.ReadValue(): {0}", ex);
                        value = null;
                    }

                    //Console.WriteLine ("Message Property (unhandled): {0} = {1}", prop.PropertyTag.Id, value);
                    Assert.AreEqual(type, value.GetType(), "Unexpected value type for {0}: {1}", prop.PropertyTag, value.GetType().Name);
                    break;
                }
            }

            if (string.IsNullOrEmpty(message.Subject) && !string.IsNullOrEmpty(normalizedSubject))
            {
                if (!string.IsNullOrEmpty(subjectPrefix))
                {
                    message.Subject = subjectPrefix + normalizedSubject;
                }
                else
                {
                    message.Subject = normalizedSubject;
                }
            }
        }