示例#1
0
        public void TestEncodedWordInvalidEncoding()
        {
            const string text   = "blurdy bloop =?iso-8859-1?x?invalid_encoding?= beep boop";
            var          buffer = Encoding.UTF8.GetBytes(text);
            string       result;

            result = Rfc2047.DecodePhrase(buffer);
            Assert.AreEqual(text, result);

            result = Rfc2047.DecodeText(buffer);
            Assert.AreEqual(text, result);
        }
示例#2
0
        public void EncodeTextWithAllowMixedHeaderCharsetsFormatOptions()
        {
            var text = "50304_2201_2021_Contract_Main_2021-11-04.pdf";
            var encodingOptionsWithAllowMixedHeaderCharsets = new FormatOptions {
                International = false, MaxLineLength = 988, AllowMixedHeaderCharsets = true
            };

            var encodedString = Rfc2047.EncodeText(encodingOptionsWithAllowMixedHeaderCharsets, Encoding.UTF8, text);
            var decodedString = Rfc2047.DecodeText(encodedString);

            Assert.AreEqual(text, decodedString);
        }
示例#3
0
        public void TestEncodedWordIncompleteCharset()
        {
            const string text   = "blurdy bloop =?iso-8859-1";
            var          buffer = Encoding.UTF8.GetBytes(text);
            string       result;

            result = Rfc2047.DecodePhrase(buffer);
            Assert.AreEqual(text, result);

            result = Rfc2047.DecodeText(buffer);
            Assert.AreEqual(text, result);
        }
示例#4
0
        internal override void Encode(FormatOptions options, StringBuilder builder, bool firstToken, ref int lineLength)
        {
            if (!string.IsNullOrEmpty(Name))
            {
                string name;

                if (!options.International)
                {
                    var encoded = Rfc2047.EncodePhrase(options, Encoding, Name);
                    name = Encoding.ASCII.GetString(encoded, 0, encoded.Length);
                }
                else
                {
                    name = EncodeInternationalizedPhrase(Name);
                }

                if (lineLength + name.Length > options.MaxLineLength)
                {
                    if (name.Length > options.MaxLineLength)
                    {
                        // we need to break up the name...
                        builder.AppendFolded(options, firstToken, name, ref lineLength);
                    }
                    else
                    {
                        // the name itself is short enough to fit on a single line,
                        // but only if we write it on a line by itself
                        if (!firstToken && lineLength > 1)
                        {
                            builder.LineWrap(options);
                            lineLength = 1;
                        }

                        lineLength += name.Length;
                        builder.Append(name);
                    }
                }
                else
                {
                    // we can safely fit the name on this line...
                    lineLength += name.Length;
                    builder.Append(name);
                }
            }

            builder.Append(": ");
            lineLength += 2;

            Members.Encode(options, builder, false, ref lineLength);

            builder.Append(';');
            lineLength++;
        }
示例#5
0
        public void TestFoldPreFoldedHeaderValue()
        {
            const string expected = " This is a pre\r\n folded header value.\r\n";
            const string text     = "This is a pre\r\n folded header value.";
            var          options  = FormatOptions.Default.Clone();

            options.NewLineFormat = NewLineFormat.Dos;

            var result = Encoding.ASCII.GetString(Rfc2047.FoldUnstructuredHeader(options, "Subject", Encoding.ASCII.GetBytes(text)));

            Assert.AreEqual(expected, result);
        }
示例#6
0
        public void TestFoldReallyLongWordToken()
        {
            const string expected = " This header value has a\r\n really-really-really-really-long-rfc0822-word-token-that-exceeds-the-max-allo\r\n wable-line-length-and-must-be-folded lets see what MimeKit does...\r\n";
            const string text     = "This header value has a really-really-really-really-long-rfc0822-word-token-that-exceeds-the-max-allowable-line-length-and-must-be-folded lets see what MimeKit does...";
            var          options  = FormatOptions.Default.Clone();

            options.NewLineFormat = NewLineFormat.Dos;

            var result = Encoding.ASCII.GetString(Rfc2047.FoldUnstructuredHeader(options, "Subject", Encoding.ASCII.GetBytes(text)));

            Assert.AreEqual(expected, result);
        }
示例#7
0
        public void TestEncodeSurrogatePair()
        {
            const string expected = "I'm so happy! =?utf-8?b?8J+YgA==?= I love MIME so much =?utf-8?b?4p2k77iP4oCN8J+UpSE=?= Isn't it great?";
            const string text     = "I'm so happy! 😀 I love MIME so much ❤️‍🔥! Isn't it great?";
            string       result;

            result = Encoding.ASCII.GetString(Rfc2047.EncodePhrase(Encoding.UTF8, text));
            Assert.AreEqual(expected, result, "EncodePhrase");

            result = Encoding.ASCII.GetString(Rfc2047.EncodeText(Encoding.UTF8, text));
            Assert.AreEqual(expected, result, "EncodeText");
        }
示例#8
0
        public void TestEncodeControls()
        {
            const string expected = "I'm so happy! =?utf-8?q?=07?= I love MIME so much =?utf-8?q?=07=07!?= Isn't it great?";
            const string text     = "I'm so happy! \a I love MIME so much \a\a! Isn't it great?";
            string       result;

            result = Encoding.ASCII.GetString(Rfc2047.EncodePhrase(Encoding.UTF8, text));
            Assert.AreEqual(expected, result, "EncodePhrase");

            result = Encoding.ASCII.GetString(Rfc2047.EncodeText(Encoding.UTF8, text));
            Assert.AreEqual(expected, result, "EncodeText");
        }
示例#9
0
        public void TestEncodedWordEmptyCharsetWithLang()
        {
            const string text   = "blurdy bloop =?*en?q?no_charset?= beep boop";
            var          buffer = Encoding.UTF8.GetBytes(text);
            string       result;

            result = Rfc2047.DecodePhrase(buffer);
            Assert.AreEqual(text, result);

            result = Rfc2047.DecodeText(buffer);
            Assert.AreEqual(text, result);
        }
示例#10
0
        public void TestEncodeWrongCharset()
        {
            const string expected = "I'm so happy! =?utf-8?b?5ZCN44GM44OJ44Oh44Kk44Oz?= I love MIME so much =?utf-8?b?4p2k77iP4oCN8J+UpSE=?= Isn't it great?";
            const string text     = "I'm so happy! 名がドメイン I love MIME so much ❤️‍🔥! Isn't it great?";
            var          latin1   = Encoding.GetEncoding("iso-8859-1", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
            string       result;

            result = Encoding.ASCII.GetString(Rfc2047.EncodePhrase(latin1, text));
            Assert.AreEqual(expected, result, "EncodePhrase");

            result = Encoding.ASCII.GetString(Rfc2047.EncodeText(latin1, text));
            Assert.AreEqual(expected, result, "EncodeText");
        }
示例#11
0
        public void TestEncodedWordWithLang()
        {
            const string text     = "blurdy bloop =?iso-8859-1*en?q?this_is_english?= beep boop";
            const string expected = "blurdy bloop this is english beep boop";
            var          buffer   = Encoding.UTF8.GetBytes(text);
            string       result;

            result = Rfc2047.DecodePhrase(buffer);
            Assert.AreEqual(expected, result);

            result = Rfc2047.DecodeText(buffer);
            Assert.AreEqual(expected, result);
        }
示例#12
0
        static byte[] EncodeUnstructuredHeader(ParserOptions options, FormatOptions format, Encoding charset, string field, string value)
        {
            if (format.International)
            {
                var folded = Fold(format, field, value);

                return(Encoding.UTF8.GetBytes(folded));
            }

            var encoded = Rfc2047.EncodeText(format, charset, value);

            return(Rfc2047.FoldUnstructuredHeader(format, field, encoded));
        }
示例#13
0
        /// <summary>
        /// Gets the header value using the specified charset.
        /// </summary>
        /// <remarks>
        /// <para>If the raw header value does not properly encode non-ASCII text, the decoder
        /// will fall back to a default charset encoding. Sometimes, however, this
        /// default charset fallback is wrong and the mail client may wish to override
        /// that default charset on a per-header basis.</para>
        /// <para>By using this method, the client is able to override the fallback charset
        /// on a per-header basis.</para>
        /// </remarks>
        /// <returns>The value.</returns>
        /// <param name="charset">Charset.</param>
        public string GetValue(Encoding charset)
        {
            if (charset == null)
            {
                throw new ArgumentNullException("charset");
            }

            var options = Options.Clone();

            options.CharsetEncoding = charset;

            return(Unfold(Rfc2047.DecodeText(options, RawValue)));
        }
示例#14
0
        static void AddEnvelopeAddress(InternetAddressList list, ImapEngine engine, CancellationToken cancellationToken)
        {
            var       values = new string[4];
            ImapToken token;
            int       index = 0;

            do
            {
                token = engine.ReadToken(cancellationToken);

                switch (token.Type)
                {
                case ImapTokenType.Literal:
                    values[index] = engine.ReadLiteral(cancellationToken);
                    break;

                case ImapTokenType.QString:
                case ImapTokenType.Atom:
                    values[index] = (string)token.Value;
                    break;

                case ImapTokenType.Nil:
                    break;

                default:
                    throw ImapEngine.UnexpectedToken(token, false);
                }

                index++;
            } while (index < 4);

            token = engine.ReadToken(cancellationToken);

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

            string name = null;

            if (values[0] != null)
            {
                // Note: since the ImapEngine.ReadLiteral() uses iso-8859-1
                // to convert bytes to unicode, we can undo that here:
                name = Rfc2047.DecodePhrase(Latin1.GetBytes(values[0]));
            }

            string address = values[3] != null ? values[2] + "@" + values[3] : values[2];

            list.Add(new MailboxAddress(name, address));
        }
示例#15
0
        public void TestRfc2047DecodeInvalidPayloadBreak()
        {
            const string japanese = "狂ったこの世で狂うなら気は確かだ。";
            var          utf8     = Encoding.UTF8.GetBytes(japanese);
            var          base64   = Convert.ToBase64String(utf8);
            var          builder  = new StringBuilder();

            builder.Append("=?utf-8?b?").Append(base64.Substring(0, base64.Length - 6)).Append("?= ");
            builder.Append("=?utf-8?b?").Append(base64.Substring(base64.Length - 6)).Append("?=");

            var decoded = Rfc2047.DecodeText(Encoding.ASCII.GetBytes(builder.ToString()));

            Assert.AreEqual(japanese, decoded, "Decoded text did not match the original.");
        }
示例#16
0
        public void TestSimpleRfc2047QEncodedPhrase()
        {
            var    options = ParserOptions.Default.Clone();
            var    input   = "=?iso-8859-1?q?hola?=";
            string actual;

            options.EnableRfc2047Workarounds = false;
            actual = Rfc2047.DecodePhrase(options, Encoding.ASCII.GetBytes(input));
            Assert.AreEqual("hola", actual);

            options.EnableRfc2047Workarounds = true;
            actual = Rfc2047.DecodePhrase(options, Encoding.ASCII.GetBytes(input));
            Assert.AreEqual("hola", actual, "Unexpected result when workarounds enabled.");
        }
示例#17
0
        public void TestArgumentExceptions()
        {
            var text = Encoding.UTF8.GetBytes("this is some text");

            // DecodePhrase
            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodePhrase(null, text, 0, text.Length));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodePhrase(ParserOptions.Default, null, 0, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodePhrase(ParserOptions.Default, text, -1, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodePhrase(ParserOptions.Default, text, 0, -1));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodePhrase(null, 0, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodePhrase(text, -1, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodePhrase(text, 0, -1));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodePhrase(null, text));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodePhrase(ParserOptions.Default, null));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodePhrase(null));

            // DecodeText
            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodeText(null, text, 0, text.Length));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodeText(ParserOptions.Default, null, 0, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodeText(ParserOptions.Default, text, -1, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodeText(ParserOptions.Default, text, 0, -1));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodeText(null, 0, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodeText(text, -1, text.Length));
            Assert.Throws <ArgumentOutOfRangeException> (() => Rfc2047.DecodeText(text, 0, -1));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodeText(null, text));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodeText(ParserOptions.Default, null));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.DecodeText(null));

            // EncodePhrase
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodePhrase(null, Encoding.UTF8, "phrase"));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodePhrase(FormatOptions.Default, null, "phrase"));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodePhrase(FormatOptions.Default, Encoding.UTF8, null));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodePhrase(null, "phrase"));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodePhrase(Encoding.UTF8, null));

            // EncodeText
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodeText(null, Encoding.UTF8, "text"));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodeText(FormatOptions.Default, null, "text"));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodeText(FormatOptions.Default, Encoding.UTF8, null));

            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodeText(null, "text"));
            Assert.Throws <ArgumentNullException> (() => Rfc2047.EncodeText(Encoding.UTF8, null));
        }
示例#18
0
        public void TestDecodeInvalidCharset()
        {
            const string xunknown = "=?x-unknown?B?aG9sYQ==?=";
            const string cp1260   = "=?cp1260?B?aG9sYQ==?=";
            string       actual;

            // Note: we won't be able to get a codepage for x-unknown.
            actual = Rfc2047.DecodeText(Encoding.ASCII.GetBytes(xunknown));
            Assert.AreEqual("hola", actual, "Unexpected decoding of x-unknown.");

            // Note: cp-1260 doesn't exist, but will make CharsetUtils parse the codepage as 1260.
            actual = Rfc2047.DecodeText(Encoding.ASCII.GetBytes(cp1260));
            Assert.AreEqual("hola", actual, "Unexpected decoding of cp1260.");
        }
示例#19
0
        public void TestSimpleRfc2047QEncodedText()
        {
            var    options = ParserOptions.Default.Clone();
            var    input   = "=?iso-8859-1?q?hola?=";
            string actual;

            options.Rfc2047ComplianceMode = RfcComplianceMode.Strict;
            actual = Rfc2047.DecodeText(options, Encoding.ASCII.GetBytes(input));
            Assert.AreEqual("hola", actual);

            options.Rfc2047ComplianceMode = RfcComplianceMode.Loose;
            actual = Rfc2047.DecodeText(options, Encoding.ASCII.GetBytes(input));
            Assert.AreEqual("hola", actual, "Unexpected result when workarounds enabled.");
        }
示例#20
0
        public void TestDecodeEmptyString()
        {
            var empty = new byte[0];

            Assert.AreEqual(string.Empty, Rfc2047.DecodePhrase(empty));
            Assert.AreEqual(string.Empty, Rfc2047.DecodePhrase(empty, 0, 0));
            Assert.AreEqual(string.Empty, Rfc2047.DecodePhrase(ParserOptions.Default, empty));
            Assert.AreEqual(string.Empty, Rfc2047.DecodePhrase(ParserOptions.Default, empty, 0, 0));
            Assert.AreEqual(string.Empty, Rfc2047.DecodePhrase(ParserOptions.Default, empty, 0, 0, out _));

            Assert.AreEqual(string.Empty, Rfc2047.DecodeText(empty));
            Assert.AreEqual(string.Empty, Rfc2047.DecodeText(empty, 0, 0));
            Assert.AreEqual(string.Empty, Rfc2047.DecodeText(ParserOptions.Default, empty));
            Assert.AreEqual(string.Empty, Rfc2047.DecodeText(ParserOptions.Default, empty, 0, 0));
            Assert.AreEqual(string.Empty, Rfc2047.DecodeText(ParserOptions.Default, empty, 0, 0, out _));
        }
示例#21
0
        public void TestRfc2047DecodeInvalidMultibyteBreak()
        {
            const string japanese = "狂ったこの世で狂うなら気は確かだ。";
            var          utf8     = Encoding.UTF8.GetBytes(japanese);
            var          builder  = new StringBuilder();

            for (int wordBreak = (utf8.Length / 2) - 5; wordBreak < (utf8.Length / 2) + 5; wordBreak++)
            {
                builder.Append("=?utf-8?b?").Append(Convert.ToBase64String(utf8, 0, wordBreak)).Append("?= ");
                builder.Append("=?utf-8?b?").Append(Convert.ToBase64String(utf8, wordBreak, utf8.Length - wordBreak)).Append("?=");

                var decoded = Rfc2047.DecodeText(Encoding.ASCII.GetBytes(builder.ToString()));

                Assert.AreEqual(japanese, decoded, "Decoded text did not match the original.");

                builder.Clear();
            }
        }
示例#22
0
        /// <summary>
        /// Sets the header value using the specified charset.
        /// </summary>
        /// <param name="charset">A charset encoding.</param>
        /// <param name="value">The header value.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="charset"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="value"/> is <c>null</c>.</para>
        /// </exception>
        public void SetValue(Encoding charset, string value)
        {
            if (charset == null)
            {
                throw new ArgumentNullException("charset");
            }

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

            textValue = Unfold(value.Trim());

            var encoded = Rfc2047.EncodeText(FormatOptions.Default, charset, textValue);

            RawValue = Rfc2047.FoldUnstructuredHeader(FormatOptions.Default, Field, encoded);
            OnChanged();
        }
示例#23
0
        public void TestEncodingLongNameMixedQuotingAndEncoding()
        {
            const string name           = "Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx für xxxxxxxxxxxxx xxxx";
            const string encodedName    = "\"Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx\" =?iso-8859-1?b?Zvxy?= xxxxxxxxxxxxx xxxx";
            const string encodedMailbox = "\"Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx\" =?iso-8859-1?b?Zvxy?= xxxxxxxxxxxxx\n xxxx <*****@*****.**>";
            const string address        = "*****@*****.**";
            var          buffer         = Rfc2047.EncodePhrase(Encoding.UTF8, name);
            var          result         = Encoding.UTF8.GetString(buffer);

            Assert.AreEqual(encodedName, result);

            var mailbox = new MailboxAddress(name, address);
            var list    = new InternetAddressList();

            list.Add(mailbox);

            result = list.ToString(true);

            Assert.AreEqual(encodedMailbox, result);
        }
示例#24
0
        static string ReadNStringToken(ImapEngine engine, bool rfc2047, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken (cancellationToken);
            string value;

            switch (token.Type) {
            case ImapTokenType.Literal:
                value = engine.ReadLiteral (cancellationToken);
                break;
            case ImapTokenType.QString:
            case ImapTokenType.Atom:
                value = (string) token.Value;
                break;
            case ImapTokenType.Nil:
                return null;
            default:
                throw ImapEngine.UnexpectedToken (token, false);
            }

            return rfc2047 ? Rfc2047.DecodeText (Latin1.GetBytes (value)) : value;
        }
示例#25
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out InternetAddress address)
        {
            address = null;

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            // keep track of the start & length of the phrase
            int startIndex = index;
            int length     = 0;

            while (index < endIndex && ParseUtils.Skip8bitWord(text, ref index, endIndex, throwOnError))
            {
                length = index - startIndex;

                do
                {
                    if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                    {
                        return(false);
                    }

                    // Note: some clients don't quote dots in the name
                    if (index >= endIndex || text[index] != (byte)'.')
                    {
                        break;
                    }

                    index++;
                } while (true);
            }

            if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
            {
                return(false);
            }

            // specials    =  "(" / ")" / "<" / ">" / "@"  ; Must be in quoted-
            //             /  "," / ";" / ":" / "\" / <">  ;  string, to use
            //             /  "." / "[" / "]"              ;  within a word.

            if (index >= endIndex || text[index] == (byte)',' || text[index] == ';')
            {
                // we've completely gobbled up an addr-spec w/o a domain
                byte   sentinel = index < endIndex ? text[index] : (byte)',';
                string name, addrspec;

                // rewind back to the beginning of the local-part
                index = startIndex;

                if (!TryParseAddrspec(text, ref index, endIndex, sentinel, throwOnError, out addrspec))
                {
                    return(false);
                }

                ParseUtils.SkipWhiteSpace(text, ref index, endIndex);

                if (index < endIndex && text[index] == '(')
                {
                    int comment = index;

                    if (!ParseUtils.SkipComment(text, ref index, endIndex))
                    {
                        if (throwOnError)
                        {
                            throw new ParseException(string.Format("Incomplete comment token at offset {0}", comment), comment, index);
                        }

                        return(false);
                    }

                    comment++;

                    name = Rfc2047.DecodePhrase(options, text, comment, (index - 1) - comment).Trim();
                }
                else
                {
                    name = string.Empty;
                }

                address = new MailboxAddress(name, addrspec);

                return(true);
            }

            if (text[index] == (byte)':')
            {
                // rfc2822 group address
                int    codepage;
                string name;

                if (length > 0)
                {
                    name = Rfc2047.DecodePhrase(options, text, startIndex, length, out codepage);
                }
                else
                {
                    name     = string.Empty;
                    codepage = 65001;
                }

                return(TryParseGroup(options, text, startIndex, ref index, endIndex, MimeUtils.Unquote(name), codepage, throwOnError, out address));
            }

            if (text[index] == (byte)'<')
            {
                // rfc2822 angle-addr token
                int    codepage;
                string name;

                if (length > 0)
                {
                    name = Rfc2047.DecodePhrase(options, text, startIndex, length, out codepage);
                }
                else
                {
                    name     = string.Empty;
                    codepage = 65001;
                }

                return(TryParseMailbox(text, startIndex, ref index, endIndex, MimeUtils.Unquote(name), codepage, throwOnError, out address));
            }

            if (text[index] == (byte)'@')
            {
                // we're either in the middle of an addr-spec token or we completely gobbled up an addr-spec w/o a domain
                string name, addrspec;

                // rewind back to the beginning of the local-part
                index = startIndex;

                if (!TryParseAddrspec(text, ref index, endIndex, (byte)',', throwOnError, out addrspec))
                {
                    return(false);
                }

                ParseUtils.SkipWhiteSpace(text, ref index, endIndex);

                if (index < endIndex && text[index] == '(')
                {
                    int comment = index;

                    if (!ParseUtils.SkipComment(text, ref index, endIndex))
                    {
                        if (throwOnError)
                        {
                            throw new ParseException(string.Format("Incomplete comment token at offset {0}", comment), comment, index);
                        }

                        return(false);
                    }

                    comment++;

                    name = Rfc2047.DecodePhrase(options, text, comment, (index - 1) - comment).Trim();
                }
                else
                {
                    name = string.Empty;
                }

                address = new MailboxAddress(name, addrspec);

                return(true);
            }

            if (throwOnError)
            {
                throw new ParseException(string.Format("Invalid address token at offset {0}", startIndex), startIndex, index);
            }

            return(false);
        }
示例#26
0
        internal override void Encode(FormatOptions options, StringBuilder builder, ref int lineLength)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }

            if (lineLength < 0)
            {
                throw new ArgumentOutOfRangeException("lineLength");
            }

            if (!string.IsNullOrEmpty(Name))
            {
                string name;

                if (!options.International)
                {
                    var encoded = Rfc2047.EncodePhrase(options, Encoding, Name);
                    name = Encoding.ASCII.GetString(encoded, 0, encoded.Length);
                }
                else
                {
                    name = EncodeInternationalizedPhrase(Name);
                }

                if (lineLength + name.Length > options.MaxLineLength)
                {
                    if (name.Length > options.MaxLineLength)
                    {
                        // we need to break up the name...
                        builder.AppendFolded(options, name, ref lineLength);
                    }
                    else
                    {
                        // the name itself is short enough to fit on a single line,
                        // but only if we write it on a line by itself
                        if (lineLength > 1)
                        {
                            builder.LineWrap(options);
                            lineLength = 1;
                        }

                        lineLength += name.Length;
                        builder.Append(name);
                    }
                }
                else
                {
                    // we can safely fit the name on this line...
                    lineLength += name.Length;
                    builder.Append(name);
                }
            }

            builder.Append(": ");
            lineLength += 2;

            foreach (var member in Members)
            {
                member.Encode(options, builder, ref lineLength);
            }
        }
示例#27
0
        static int Rfc2047EncodeNextChunk(StringBuilder str, string text, ref int index, Encoding encoding, string charset, Encoder encoder, int maxLength)
        {
            int  byteCount = 0, charCount = 0, encodeCount = 0;
            var  buffer = new char[2];
            int  startIndex = index;
            int  nchars, n;
            char c;

            while (index < text.Length)
            {
                c = text[index++];

                if (c < 127)
                {
                    if (IsCtrl(c) || c == '"' || c == '\\')
                    {
                        encodeCount++;
                    }

                    byteCount++;
                    charCount++;
                    nchars = 1;
                    n      = 1;
                }
                else if (c < 256)
                {
                    // iso-8859-1
                    encodeCount++;
                    byteCount++;
                    charCount++;
                    nchars = 1;
                    n      = 1;
                }
                else
                {
                    if (char.IsSurrogatePair(text, index - 1))
                    {
                        buffer[1] = text[index++];
                        nchars    = 2;
                    }
                    else
                    {
                        nchars = 1;
                    }

                    buffer[0] = c;

                    try {
                        n = encoder.GetByteCount(buffer, 0, nchars, true);
                    } catch {
                        n = 3;
                    }

                    charCount   += nchars;
                    encodeCount += n;
                    byteCount   += n;
                }

                if (ExceedsMaxWordLength(charset, byteCount, encodeCount, maxLength))
                {
                    // restore our previous state
                    charCount -= nchars;
                    index     -= nchars;
                    byteCount -= n;
                    break;
                }
            }

            return(Rfc2047.AppendEncodedWord(str, encoding, text, startIndex, charCount, QEncodeMode.Text));
        }
示例#28
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ParameterList paramList)
        {
            var rfc2184 = new Dictionary <string, List <NameValuePair> > (icase);
            var @params = new List <NameValuePair> ();
            List <NameValuePair> parts;

            paramList = null;

            do
            {
                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (index >= endIndex)
                {
                    break;
                }

                // handle empty parameter name/value pairs
                if (text[index] == (byte)';')
                {
                    index++;
                    continue;
                }

                NameValuePair pair;
                if (!TryParseNameValuePair(text, ref index, endIndex, throwOnError, out pair))
                {
                    return(false);
                }

                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (pair.Id.HasValue)
                {
                    if (rfc2184.TryGetValue(pair.Name, out parts))
                    {
                        parts.Add(pair);
                    }
                    else
                    {
                        parts = new List <NameValuePair> ();
                        rfc2184[pair.Name] = parts;
                        @params.Add(pair);
                        parts.Add(pair);
                    }
                }
                else
                {
                    @params.Add(pair);
                }

                if (index >= endIndex)
                {
                    break;
                }

                if (text[index] != (byte)';')
                {
                    if (throwOnError)
                    {
                        throw new ParseException(string.Format("Invalid parameter list token at offset {0}", index), index, index);
                    }

                    return(false);
                }

                index++;
            } while (true);

            paramList = new ParameterList();
            var hex = new HexDecoder();

            foreach (var param in @params)
            {
                int     startIndex = param.ValueStart;
                int     length     = param.ValueLength;
                Decoder decoder    = null;
                string  value;

                if (param.Id.HasValue)
                {
                    parts = rfc2184[param.Name];
                    parts.Sort();

                    value = string.Empty;
                    for (int i = 0; i < parts.Count; i++)
                    {
                        startIndex = parts[i].ValueStart;
                        length     = parts[i].ValueLength;

                        if (parts[i].Encoded)
                        {
                            bool flush = i + 1 >= parts.Count || !parts[i + 1].Encoded;

                            // Note: Some mail clients mistakenly quote encoded parameter values when they shouldn't
                            if (length >= 2 && text[startIndex] == (byte)'"' && text[startIndex + length - 1] == (byte)'"')
                            {
                                startIndex++;
                                length -= 2;
                            }

                            value += DecodeRfc2184(ref decoder, hex, text, startIndex, length, flush);
                        }
                        else if (length >= 2 && text[startIndex] == (byte)'"')
                        {
                            var quoted = CharsetUtils.ConvertToUnicode(options, text, startIndex, length);
                            value += MimeUtils.Unquote(quoted);
                            hex.Reset();
                        }
                        else if (length > 0)
                        {
                            value += CharsetUtils.ConvertToUnicode(options, text, startIndex, length);
                            hex.Reset();
                        }
                    }
                    hex.Reset();
                }
                else if (param.Encoded)
                {
                    value = DecodeRfc2184(ref decoder, hex, text, startIndex, length, true);
                    hex.Reset();
                }
                else if (!paramList.Contains(param.Name))
                {
                    // Note: If we've got an rfc2184-encoded version of the same parameter, then
                    // we'll want to choose that one as opposed to the ASCII variant (i.e. this one).
                    //
                    // While most mail clients that I know of do not send multiple parameters of the
                    // same name, rfc6266 suggests that HTTP servers are using this approach to work
                    // around HTTP clients that do not (yet) implement support for the rfc2184/2231
                    // encoding of parameter values. Since none of the MIME specifications provide
                    // any suggestions for dealing with this, following rfc6266 seems to make the
                    // most sense, even though it is meant for HTTP clients and servers.
                    if (length >= 2 && text[startIndex] == (byte)'"')
                    {
                        var quoted = Rfc2047.DecodeText(options, text, startIndex, length);
                        value = MimeUtils.Unquote(quoted);
                    }
                    else if (length > 0)
                    {
                        value = Rfc2047.DecodeText(options, text, startIndex, length);
                    }
                    else
                    {
                        value = string.Empty;
                    }
                }
                else
                {
                    continue;
                }

                paramList[param.Name] = value;
            }

            return(true);
        }
示例#29
0
        internal override void Encode(FormatOptions options, StringBuilder builder, ref int lineLength)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }

            if (lineLength < 0)
            {
                throw new ArgumentOutOfRangeException("lineLength");
            }

            string route = Route.ToString();

            if (!string.IsNullOrEmpty(route))
            {
                route += ":";
            }

            if (!string.IsNullOrEmpty(Name))
            {
                string name;

                if (!options.International)
                {
                    var encoded = Rfc2047.EncodePhrase(options, Encoding, Name);
                    name = Encoding.ASCII.GetString(encoded, 0, encoded.Length);
                }
                else
                {
                    name = EncodeInternationalizedPhrase(Name);
                }

                if (lineLength + name.Length > options.MaxLineLength)
                {
                    if (name.Length > options.MaxLineLength)
                    {
                        // we need to break up the name...
                        builder.AppendFolded(options, name, ref lineLength);
                    }
                    else
                    {
                        // the name itself is short enough to fit on a single line,
                        // but only if we write it on a line by itself
                        if (lineLength > 1)
                        {
                            builder.LineWrap(options);
                            lineLength = 1;
                        }

                        lineLength += name.Length;
                        builder.Append(name);
                    }
                }
                else
                {
                    // we can safely fit the name on this line...
                    lineLength += name.Length;
                    builder.Append(name);
                }

                if ((lineLength + route.Length + Address.Length + 3) > options.MaxLineLength)
                {
                    builder.Append(options.NewLine);
                    builder.Append("\t<");
                    lineLength = 2;
                }
                else
                {
                    builder.Append(" <");
                    lineLength += 2;
                }

                lineLength += route.Length;
                builder.Append(route);

                lineLength += Address.Length + 1;
                builder.Append(Address);
                builder.Append('>');
            }
            else if (!string.IsNullOrEmpty(route))
            {
                if ((lineLength + route.Length + Address.Length + 2) > options.MaxLineLength)
                {
                    builder.Append(options.NewLine);
                    builder.Append("\t<");
                    lineLength = 2;
                }
                else
                {
                    builder.Append('<');
                    lineLength++;
                }

                lineLength += route.Length;
                builder.Append(route);

                lineLength += Address.Length + 1;
                builder.Append(Address);
                builder.Append('>');
            }
            else
            {
                if ((lineLength + Address.Length) > options.MaxLineLength)
                {
                    builder.LineWrap(options);
                    lineLength = 1;
                }

                lineLength += Address.Length;
                builder.Append(Address);
            }
        }
示例#30
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ParameterList paramList)
        {
            var rfc2231 = new Dictionary <string, List <NameValuePair> > (MimeUtils.OrdinalIgnoreCase);
            var @params = new List <NameValuePair> ();
            List <NameValuePair> parts;

            paramList = null;

            do
            {
                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (index >= endIndex)
                {
                    break;
                }

                // handle empty parameter name/value pairs
                if (text[index] == (byte)';')
                {
                    index++;
                    continue;
                }

                NameValuePair pair;
                if (!TryParseNameValuePair(options, text, ref index, endIndex, throwOnError, out pair))
                {
                    return(false);
                }

                if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                if (pair.Id.HasValue)
                {
                    if (rfc2231.TryGetValue(pair.Name, out parts))
                    {
                        parts.Add(pair);
                    }
                    else
                    {
                        parts = new List <NameValuePair> ();
                        rfc2231[pair.Name] = parts;
                        @params.Add(pair);
                        parts.Add(pair);
                    }
                }
                else
                {
                    @params.Add(pair);
                }

                if (index >= endIndex)
                {
                    break;
                }

                if (text[index] != (byte)';')
                {
                    if (throwOnError)
                    {
                        throw new ParseException(string.Format("Invalid parameter list token at offset {0}", index), index, index);
                    }

                    return(false);
                }

                index++;
            } while (true);

            paramList = new ParameterList();
            var hex = new HexDecoder();

            foreach (var param in @params)
            {
                var       method     = ParameterEncodingMethod.Default;
                int       startIndex = param.ValueStart;
                int       length     = param.ValueLength;
                var       buffer     = param.Value;
                Encoding  encoding   = null;
                Decoder   decoder    = null;
                Parameter parameter;
                string    value;

                if (param.Id.HasValue)
                {
                    method = ParameterEncodingMethod.Rfc2231;
                    parts  = rfc2231[param.Name];
                    parts.Sort();

                    value = string.Empty;

                    for (int i = 0; i < parts.Count; i++)
                    {
                        startIndex = parts[i].ValueStart;
                        length     = parts[i].ValueLength;
                        buffer     = parts[i].Value;

                        if (parts[i].Encoded)
                        {
                            bool     flush = i + 1 >= parts.Count || !parts[i + 1].Encoded;
                            Encoding charset;

                            // Note: Some mail clients mistakenly quote encoded parameter values when they shouldn't
                            if (length >= 2 && buffer[startIndex] == (byte)'"' && buffer[startIndex + length - 1] == (byte)'"')
                            {
                                startIndex++;
                                length -= 2;
                            }

                            value   += DecodeRfc2231(out charset, ref decoder, hex, buffer, startIndex, length, flush);
                            encoding = encoding ?? charset;
                        }
                        else if (length >= 2 && buffer[startIndex] == (byte)'"')
                        {
                            var quoted = CharsetUtils.ConvertToUnicode(options, buffer, startIndex, length);
                            value += MimeUtils.Unquote(quoted);
                            hex.Reset();
                        }
                        else if (length > 0)
                        {
                            value += CharsetUtils.ConvertToUnicode(options, buffer, startIndex, length);
                            hex.Reset();
                        }
                    }
                    hex.Reset();
                }
                else if (param.Encoded)
                {
                    // Note: param value is not supposed to be quoted, but issue #239 illustrates
                    // that this can happen in the wild. Hopefully we will not need to worry
                    // about quoted-pairs.
                    if (length >= 2 && buffer[startIndex] == (byte)'"')
                    {
                        if (buffer[startIndex + length - 1] == (byte)'"')
                        {
                            length--;
                        }

                        startIndex++;
                        length--;
                    }

                    value  = DecodeRfc2231(out encoding, ref decoder, hex, buffer, startIndex, length, true);
                    method = ParameterEncodingMethod.Rfc2231;
                    hex.Reset();
                }
                else if (!paramList.Contains(param.Name))
                {
                    // Note: If we've got an rfc2231-encoded version of the same parameter, then
                    // we'll want to choose that one as opposed to the ASCII variant (i.e. this one).
                    //
                    // While most mail clients that I know of do not send multiple parameters of the
                    // same name, rfc6266 suggests that HTTP servers are using this approach to work
                    // around HTTP clients that do not (yet) implement support for the rfc2231
                    // encoding of parameter values. Since none of the MIME specifications provide
                    // any suggestions for dealing with this, following rfc6266 seems to make the
                    // most sense, even though it is meant for HTTP clients and servers.
                    int codepage = -1;

                    if (length >= 2 && text[startIndex] == (byte)'"')
                    {
                        var quoted = Rfc2047.DecodeText(options, buffer, startIndex, length, out codepage);
                        value = MimeUtils.Unquote(quoted);
                    }
                    else if (length > 0)
                    {
                        value = Rfc2047.DecodeText(options, buffer, startIndex, length, out codepage);
                    }
                    else
                    {
                        value = string.Empty;
                    }

                    if (codepage != -1 && codepage != 65001)
                    {
                        encoding = CharsetUtils.GetEncoding(codepage);
                        method   = ParameterEncodingMethod.Rfc2047;
                    }
                }
                else
                {
                    continue;
                }

                if (paramList.table.TryGetValue(param.Name, out parameter))
                {
                    parameter.Encoding = encoding;
                    parameter.Value    = value;
                }
                else if (encoding != null)
                {
                    paramList.Add(encoding, param.Name, value);
                    parameter = paramList[paramList.Count - 1];
                }
                else
                {
                    paramList.Add(param.Name, value);
                    parameter = paramList[paramList.Count - 1];
                }

                parameter.EncodingMethod = method;
            }

            return(true);
        }