示例#1
0
        /// <summary>
        /// Converts the TNEF content into a <see cref="MimeKit.MimeMessage"/>.
        /// </summary>
        /// <remarks>
        /// TNEF data often contains properties that map to <see cref="MimeKit.MimeMessage"/>
        /// headers. TNEF data also often contains file attachments which will be
        /// mapped to MIME parts.
        /// </remarks>
        /// <returns>A message representing the TNEF data in MIME format.</returns>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="MimeKit.MimePart.Content"/> property is <c>null</c>.
        /// </exception>
        public MimeMessage ConvertToMessage()
        {
            if (Content == null)
            {
                throw new InvalidOperationException("Cannot parse null TNEF data.");
            }

            int codepage = 0;

            if (!string.IsNullOrEmpty(ContentType.Charset))
            {
                if ((codepage = CharsetUtils.GetCodePage(ContentType.Charset)) == -1)
                {
                    codepage = 0;
                }
            }

            using (var reader = new TnefReader(Content.Open(), codepage, TnefComplianceMode.Loose)) {
                return(ExtractTnefMessage(reader));
            }
        }
示例#2
0
        public void TestArgumentExceptions()
        {
            var buffer = new byte[10];

            Assert.Throws <ArgumentNullException> (() => CharsetUtils.ConvertToUnicode((ParserOptions)null, buffer, 0, buffer.Length));
            Assert.Throws <ArgumentNullException> (() => CharsetUtils.ConvertToUnicode(ParserOptions.Default, null, 0, 0));
            Assert.Throws <ArgumentOutOfRangeException> (() => CharsetUtils.ConvertToUnicode(ParserOptions.Default, buffer, -1, 0));
            Assert.Throws <ArgumentOutOfRangeException> (() => CharsetUtils.ConvertToUnicode(ParserOptions.Default, buffer, 0, -1));

            Assert.Throws <ArgumentNullException> (() => CharsetUtils.ConvertToUnicode((Encoding)null, buffer, 0, buffer.Length));
            Assert.Throws <ArgumentNullException> (() => CharsetUtils.ConvertToUnicode(Encoding.UTF8, null, 0, 0));
            Assert.Throws <ArgumentOutOfRangeException> (() => CharsetUtils.ConvertToUnicode(Encoding.UTF8, buffer, -1, 0));
            Assert.Throws <ArgumentOutOfRangeException> (() => CharsetUtils.ConvertToUnicode(Encoding.UTF8, buffer, 0, -1));

            Assert.Throws <ArgumentNullException> (() => CharsetUtils.GetCodePage(null));
            Assert.Throws <ArgumentNullException> (() => CharsetUtils.GetEncoding(null));
            Assert.Throws <ArgumentNullException> (() => CharsetUtils.GetEncoding(null, "fallback"));
            Assert.Throws <ArgumentNullException> (() => CharsetUtils.GetEncoding("charset", null));
            Assert.Throws <ArgumentOutOfRangeException> (() => CharsetUtils.GetEncoding(-1, "fallback"));
            Assert.Throws <ArgumentNullException> (() => CharsetUtils.GetEncoding(28591, null));
        }
示例#3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Parameter"/> class.
        /// </summary>
        /// <remarks>
        /// Creates a new parameter with the specified name and value.
        /// </remarks>
        /// <param name="charset">The character encoding.</param>
        /// <param name="name">The parameter name.</param>
        /// <param name="value">The parameter value.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="charset"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="name"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="value"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// <para><paramref name="charset"/> cannot be empty.</para>
        /// <para>-or-</para>
        /// <para><paramref name="name"/> contains illegal characters.</para>
        /// </exception>
        /// <exception cref="System.NotSupportedException">
        /// <paramref name="charset"/> is not supported.
        /// </exception>
        public Parameter(string charset, string name, string value)
        {
            if (charset == null)
            {
                throw new ArgumentNullException("charset");
            }

            if (charset.Length == 0)
            {
                throw new ArgumentException("The charset name cannot be empty.", "charset");
            }

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

            if (name.Length == 0)
            {
                throw new ArgumentException("Parameter names are not allowed to be empty.", "name");
            }

            for (int i = 0; i < name.Length; i++)
            {
                if (name[i] > 127 || !IsAttr((byte)name[i]))
                {
                    throw new ArgumentException("Illegal characters in parameter name.", "name");
                }
            }

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

            Encoding = CharsetUtils.GetEncoding(charset);
            Value    = value;
            Name     = name;
        }
示例#4
0
        public void TestParseCodePage()
        {
            Assert.AreEqual(1201, CharsetUtils.ParseCodePage("iso10646"));
            Assert.AreEqual(1201, CharsetUtils.ParseCodePage("iso-10646"));
            Assert.AreEqual(1201, CharsetUtils.ParseCodePage("iso10646-1"));
            Assert.AreEqual(1201, CharsetUtils.ParseCodePage("iso-10646-1"));

            Assert.AreEqual(28591, CharsetUtils.ParseCodePage("iso8859-1"));
            Assert.AreEqual(28591, CharsetUtils.ParseCodePage("iso8859_1"));
            Assert.AreEqual(28591, CharsetUtils.ParseCodePage("iso-8859-1"));
            Assert.AreEqual(28591, CharsetUtils.ParseCodePage("iso_8859_1"));
            Assert.AreEqual(28591, CharsetUtils.ParseCodePage("latin1"));

            Assert.AreEqual(50220, CharsetUtils.ParseCodePage("iso2022-jp"));
            Assert.AreEqual(50220, CharsetUtils.ParseCodePage("iso-2022-jp"));
            Assert.AreEqual(50220, CharsetUtils.ParseCodePage("iso_2022_jp"));
            Assert.AreEqual(50225, CharsetUtils.ParseCodePage("iso2022-kr"));
            Assert.AreEqual(50225, CharsetUtils.ParseCodePage("iso-2022-kr"));
            Assert.AreEqual(50225, CharsetUtils.ParseCodePage("iso_2022_kr"));

            Assert.AreEqual(1252, CharsetUtils.ParseCodePage("windows-cp1252"));
            Assert.AreEqual(1252, CharsetUtils.ParseCodePage("windows-1252"));
            Assert.AreEqual(1252, CharsetUtils.ParseCodePage("cp-1252"));
            Assert.AreEqual(1252, CharsetUtils.ParseCodePage("cp1252"));

            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("cp"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("ibm"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("windows"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("windows-"));

            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-8859"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-BB59"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-8859-"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-8859-A"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-2022-US"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-4999-1"));
            Assert.AreEqual(-1, CharsetUtils.ParseCodePage("iso-abcd-1"));
        }
示例#5
0
        /// <summary>
        /// Get a text preview of a stream of text in the specified charset.
        /// </summary>
        /// <remarks>
        /// Get a text preview of a stream of text in the specified charset.
        /// </remarks>
        /// <param name="stream">The original text stream.</param>
        /// <param name="charset">The charset encoding of the stream.</param>
        /// <returns>A string representing a shortened preview of the original text.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="stream"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="charset"/> is <c>null</c>.</para>
        /// </exception>
        public virtual string GetPreviewText(Stream stream, string charset)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

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

            Encoding encoding;

            try {
                encoding = CharsetUtils.GetEncoding(charset);
            } catch (NotSupportedException) {
                encoding = CharsetUtils.UTF8;
            }

            return(GetPreviewText(stream, encoding));
        }
示例#6
0
		public void TestGetMimeCharset ()
		{
			Encoding encoding;

			Assert.AreEqual ("iso-8859-1", CharsetUtils.GetMimeCharset ("latin1"));
			Assert.AreEqual ("iso-8859-1", CharsetUtils.GetMimeCharset (CharsetUtils.Latin1));
			Assert.AreEqual ("gibberish", CharsetUtils.GetMimeCharset ("gibberish"));

			Assert.AreEqual ("iso-2022-jp", CharsetUtils.GetMimeCharset (Encoding.GetEncoding (932)));
			Assert.AreEqual ("iso-2022-jp", CharsetUtils.GetMimeCharset (Encoding.GetEncoding (50220)));
			Assert.AreEqual ("iso-2022-jp", CharsetUtils.GetMimeCharset (Encoding.GetEncoding (50221)));

			try {
				encoding = Encoding.GetEncoding (50225);
			} catch (NotSupportedException) {
				encoding = null;
			}

			if (encoding != null)
				Assert.AreEqual ("euc-kr", CharsetUtils.GetMimeCharset (encoding));

			Assert.AreEqual ("euc-kr", CharsetUtils.GetMimeCharset (Encoding.GetEncoding (949)));
		}
示例#7
0
        internal void Encode(FormatOptions options, StringBuilder builder, ref int lineLength, Encoding encoding)
        {
            string quoted;

            var method = GetEncodeMethod(options, Name, Value, out quoted);

            if (method == EncodeMethod.None)
            {
                quoted = Value;
            }

            if (method != EncodeMethod.Rfc2184)
            {
                if (lineLength + 2 + Name.Length + 1 + quoted.Length >= options.MaxLineLength)
                {
                    builder.Append(";\n\t");
                    lineLength = 1;
                }
                else
                {
                    builder.Append("; ");
                    lineLength += 2;
                }

                lineLength += Name.Length + 1 + quoted.Length;
                builder.Append(Name);
                builder.Append('=');
                builder.Append(quoted);
                return;
            }

            int    maxLength = options.MaxLineLength - (Name.Length + 6);
            var    bestEncoding = GetBestEncoding(Value, encoding);
            var    charset = CharsetUtils.GetMimeCharset(bestEncoding);
            var    bytes = new byte[Math.Max(maxLength, 6)];
            var    hexbuf = new byte[bytes.Length * 3 + 3];
            var    encoder = bestEncoding.GetEncoder();
            var    chars = Value.ToCharArray();
            var    hex = new HexEncoder();
            int    index = 0, i = 0;
            string value, id;
            bool   encoded;
            int    length;

            do
            {
                encoded = GetNextValue(charset, encoder, hex, chars, ref index, ref bytes, ref hexbuf, maxLength, out value);
                length  = Name.Length + (encoded ? 1 : 0) + 1 + value.Length;

                if (i == 0 && index == chars.Length)
                {
                    if (lineLength + 2 + length >= options.MaxLineLength)
                    {
                        builder.Append(";\n\t");
                        lineLength = 1;
                    }
                    else
                    {
                        builder.Append("; ");
                        lineLength += 2;
                    }

                    builder.Append(Name);
                    if (encoded)
                    {
                        builder.Append('*');
                    }
                    builder.Append('=');
                    builder.Append(value);
                    lineLength += length;
                    return;
                }

                builder.Append(";\n\t");
                lineLength = 1;

                id      = i.ToString();
                length += id.Length + 1;

                builder.Append(Name);
                builder.Append('*');
                builder.Append(id);
                if (encoded)
                {
                    builder.Append('*');
                }
                builder.Append('=');
                builder.Append(value);
                lineLength += length;
                i++;
            } while (index < chars.Length);
        }
示例#8
0
        void EncodeRfc2231(FormatOptions options, StringBuilder builder, ref int lineLength, Encoding headerEncoding)
        {
            var    bestEncoding = options.International ? CharsetUtils.UTF8 : GetBestEncoding(Value, encoding ?? headerEncoding);
            int    maxLength = options.MaxLineLength - (Name.Length + 6);
            var    charset = CharsetUtils.GetMimeCharset(bestEncoding);
            var    encoder = (Encoder)bestEncoding.GetEncoder();
            var    bytes = new byte[Math.Max(maxLength, 6)];
            var    hexbuf = new byte[bytes.Length * 3 + 3];
            var    chars = Value.ToCharArray();
            var    hex = new HexEncoder();
            int    index = 0, i = 0;
            string value, id;
            bool   encoded;
            int    length;

            do
            {
                builder.Append(';');
                lineLength++;

                encoded = Rfc2231GetNextValue(options, charset, encoder, hex, chars, ref index, ref bytes, ref hexbuf, maxLength, out value);
                length  = Name.Length + (encoded ? 1 : 0) + 1 + value.Length;

                if (i == 0 && index == chars.Length)
                {
                    if (lineLength + 1 + length >= options.MaxLineLength)
                    {
                        builder.Append(options.NewLine);
                        builder.Append('\t');
                        lineLength = 1;
                    }
                    else
                    {
                        builder.Append(' ');
                        lineLength++;
                    }

                    builder.Append(Name);
                    if (encoded)
                    {
                        builder.Append('*');
                    }
                    builder.Append('=');
                    builder.Append(value);
                    lineLength += length;
                    return;
                }

                builder.Append(options.NewLine);
                builder.Append('\t');
                lineLength = 1;

                id      = i.ToString();
                length += id.Length + 1;

                builder.Append(Name);
                builder.Append('*');
                builder.Append(id);
                if (encoded)
                {
                    builder.Append('*');
                }
                builder.Append('=');
                builder.Append(value);
                lineLength += length;
                i++;
            } while (index < chars.Length);
        }
示例#9
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);
        }
示例#10
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);
        }
示例#11
0
        internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ContentDisposition disposition)
        {
            string type;
            int    atom;

            disposition = null;

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

            if (index >= endIndex)
            {
                if (throwOnError)
                {
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Expected atom token at position {0}", index), index, index);
                }

                return(false);
            }

            atom = index;
            if (text[index] == '"')
            {
                if (throwOnError)
                {
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Unxpected qstring token at position {0}", atom), atom, index);
                }

                // Note: This is a work-around for broken mailers that quote the disposition value...
                //
                // See https://github.com/jstedfast/MailKit/issues/486 for details.
                if (!ParseUtils.SkipQuoted(text, ref index, endIndex, throwOnError))
                {
                    return(false);
                }

                type = CharsetUtils.ConvertToUnicode(options, text, atom, index - atom);
                type = MimeUtils.Unquote(type);

                if (string.IsNullOrEmpty(type))
                {
                    type = Attachment;
                }
            }
            else
            {
                if (!ParseUtils.SkipAtom(text, ref index, endIndex))
                {
                    if (throwOnError)
                    {
                        throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Invalid atom token at position {0}", atom), atom, index);
                    }

                    // Note: this is a work-around for broken mailers that do not specify a disposition value...
                    //
                    // See https://github.com/jstedfast/MailKit/issues/486 for details.
                    if (index > atom || text[index] != (byte)';')
                    {
                        return(false);
                    }

                    type = Attachment;
                }
                else
                {
                    type = Encoding.ASCII.GetString(text, atom, index - atom);
                }
            }

            disposition             = new ContentDisposition();
            disposition.disposition = type;

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

            if (index >= endIndex)
            {
                return(true);
            }

            if (text[index] != (byte)';')
            {
                if (throwOnError)
                {
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Expected ';' at position {0}", index), index, index);
                }

                return(false);
            }

            index++;

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

            if (index >= endIndex)
            {
                return(true);
            }

            ParameterList parameters;

            if (!ParameterList.TryParse(options, text, ref index, endIndex, throwOnError, out parameters))
            {
                return(false);
            }

            disposition.Parameters = parameters;

            return(true);
        }
示例#12
0
        public void TestCharsetUtilsGetCodePage()
        {
            for (int i = 1; i < 16; i++)
            {
                int    expected, codepage;
                string name;

                name     = string.Format("iso-8859-{0}", i);
                codepage = CharsetUtils.GetCodePage(name);

                switch (i)
                {
                case 11:
                    expected = 874;
                    break;

                case 10:
                case 12:
                case 14:
                    expected = -1;
                    break;

                case 13:
                    if (Path.DirectorySeparatorChar == '\\')
                    {
                        goto default;
                    }
                    expected = -1;
                    break;

                default:
                    expected = 28590 + i;
                    break;
                }

                Assert.AreEqual(expected, codepage, "Invalid codepage for: {0}", name);
            }

            for (int i = 0; i < 10; i++)
            {
                int    expected, codepage;
                string name;

                if (i < 9)
                {
                    expected = 1250 + i;
                }
                else
                {
                    expected = -1;
                }

                name     = string.Format("windows-125{0}", i);
                codepage = CharsetUtils.GetCodePage(name);

                Assert.AreEqual(expected, codepage, "Invalid codepage for: {0}", name);

                name     = string.Format("windows-cp125{0}", i);
                codepage = CharsetUtils.GetCodePage(name);

                Assert.AreEqual(expected, codepage, "Invalid codepage for: {0}", name);

                name     = string.Format("cp125{0}", i);
                codepage = CharsetUtils.GetCodePage(name);

                Assert.AreEqual(expected, codepage, "Invalid codepage for: {0}", name);
            }

            foreach (var ibm in new int[] { 850, 852, 855, 857, 860, 861, 862, 863 })
            {
                int    codepage;
                string name;

                name     = string.Format("ibm-{0}", ibm);
                codepage = CharsetUtils.GetCodePage(name);

                Assert.AreEqual(ibm, codepage, "Invalid codepage for: {0}", name);
            }
        }
示例#13
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.Add(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;
                            value += DecodeRfc2184(ref decoder, hex, text, startIndex, length, flush);
                        }
                        else if (length >= 2 && text[startIndex] == (byte)'"')
                        {
                            // FIXME: use Rfc2047.Unquote()??
                            value += CharsetUtils.ConvertToUnicode(options, text, startIndex + 1, length - 2);
                            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 (length >= 2 && text[startIndex] == (byte)'"')
                {
                    // FIXME: use Rfc2047.Unquote()??
                    value = Rfc2047.DecodeText(options, text, startIndex + 1, length - 2);
                }
                else if (length > 0)
                {
                    value = Rfc2047.DecodeText(options, text, startIndex, length);
                }
                else
                {
                    value = string.Empty;
                }

                paramList.Add(new Parameter(param.Name, value));
            }

            return(true);
        }