コード例 #1
0
        /// <summary>
        /// Reads RFC 2047 (section 5) 'phrase' from source stream.
        /// </summary>
        /// <returns>Returns RFC 2047 (section 5) 'phrase' or null if end of stream reached.</returns>
        public string Phrase()
        {
            /* RFC 2047 5.
             *  phrase = 1*( encoded-word / word )
             *  word   = atom / quoted-string
             */

            int peek = Peek(true);

            if (peek == -1)
            {
                return(null);
            }
            else if (peek == '"')
            {
                return("\"" + QuotedString() + "\"");
            }
            else if (peek == '=')
            {
                return(EncodedWord());
            }
            else
            {
                string word = Atom();
                if (word == null)
                {
                    return(null);
                }

                // Try to encode invalid encoded-words if any mixed in text.
                word = encodedword_regex.Replace(word, delegate(Match m){
                    string encodedWord = m.Value;
                    try{
                        if (string.Equals(m.Groups["encoding"].Value, "Q", StringComparison.InvariantCultureIgnoreCase))
                        {
                            return(MIME_Utils.QDecode(Encoding.GetEncoding(m.Groups["charset"].Value), m.Groups["value"].Value));
                        }
                        else if (string.Equals(m.Groups["encoding"].Value, "B", StringComparison.InvariantCultureIgnoreCase))
                        {
                            return(Encoding.GetEncoding(m.Groups["charset"].Value).GetString(Net_Utils.FromBase64(Encoding.UTF8.GetBytes(m.Groups["value"].Value))));
                        }
                        // Failed to parse encoded-word, leave it as is. RFC 2047 6.3.
                        else
                        {
                            return(encodedWord);
                        }
                    }
                    catch {
                        // Failed to parse encoded-word, leave it as is. RFC 2047 6.3.
                        return(encodedWord);
                    }
                });

                return(word);
            }
        }
コード例 #2
0
        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static MIME_h_Unstructured Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            MIME_h_Unstructured retVal = new MIME_h_Unstructured();

            string[] name_value = value.Split(new char[] { ':' }, 2);
            if (name_value[0].Trim() == string.Empty)
            {
                throw new ParseException("Invalid header field '" + value + "' syntax.");
            }

            retVal.m_Name = name_value[0];

            retVal.m_Value = MIME_Encoding_EncodedWord.DecodeTextS(MIME_Utils.UnfoldHeader(name_value.Length == 2 ? name_value[1].TrimStart() : ""));

            retVal.m_ParseValue = value;

            return(retVal);
        }
コード例 #3
0
        /// <summary>
        /// Decodes non-ascii text with MIME <b>encoded-word</b> method. Defined in RFC 2047 2.
        /// </summary>
        /// <param name="text">Text.</param>
        /// <returns>Returns decoded text.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>text</b> is null reference.</exception>
        public static string DecodeTextS(string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException("word");
            }

            /* RFC 2047 2.
             *  encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
             *
             *  encoded-text = 1*<Any printable ASCII character other than "?" or SPACE>
             *                 ; (but see "Use of encoded-words in message
             *                 ; headers", section 5)
             *
             *  An 'encoded-word' may not be more than 75 characters long, including
             *  'charset', 'encoding', 'encoded-text', and delimiters.  If it is
             *  desirable to encode more text than will fit in an 'encoded-word' of
             *  75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may
             *  be used.
             *
             *  RFC 2231 updates.
             *      encoded-word := "=?" charset ["*" language] "?" encoded-text "?="
             */

            string retVal = text;

            retVal = encodedword_regex.Replace(retVal, delegate(Match m){
                // We have encoded word, try to decode it.
                // Also if we have continuing encoded word, we need to skip all whitespaces between words.

                string encodedWord = m.Value;
                try{
                    if (string.Equals(m.Groups["encoding"].Value, "Q", StringComparison.InvariantCultureIgnoreCase))
                    {
                        encodedWord = MIME_Utils.QDecode(Encoding.GetEncoding(m.Groups["charset"].Value), m.Groups["value"].Value);
                    }
                    else if (string.Equals(m.Groups["encoding"].Value, "B", StringComparison.InvariantCultureIgnoreCase))
                    {
                        encodedWord = Encoding.GetEncoding(m.Groups["charset"].Value).GetString(Net_Utils.FromBase64(Encoding.UTF8.GetBytes(m.Groups["value"].Value)));
                    }
                    // Failed to parse encoded-word, leave it as is. RFC 2047 6.3.
                    // else{

                    // No continuing encoded-word, append whitespaces to retval.
                    Match mNext = encodedword_regex.Match(retVal, m.Index + m.Length);
                    if (!(mNext.Success && mNext.Index == (m.Index + m.Length)))
                    {
                        encodedWord += m.Groups["whitespaces"].Value;
                    }
                    // We have continuing encoded-word, so skip all whitespaces.
                    //else{

                    return(encodedWord);
                }
                catch {
                    // Failed to parse encoded-word, leave it as is. RFC 2047 6.3.
                    return(encodedWord);
                }
            });

            return(retVal);
        }
コード例 #4
0
        /// <summary>
        /// Reads RFC 2047 'encoded-word' from source stream.
        /// </summary>
        /// <returns>Returns RFC 2047 'encoded-word' or null if end of stream reached.</returns>
        /// <exception cref="InvalidOperationException">Is raised when source stream has no encoded-word at current position.</exception>
        public string EncodedWord()
        {
            /* RFC 2047 2.
             *  encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
             *
             *  encoded-text = 1*<Any printable ASCII character other than "?" or SPACE>
             *                 ; (but see "Use of encoded-words in message
             *                 ; headers", section 5)
             *
             *  An 'encoded-word' may not be more than 75 characters long, including
             *  'charset', 'encoding', 'encoded-text', and delimiters.  If it is
             *  desirable to encode more text than will fit in an 'encoded-word' of
             *  75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may
             *  be used.
             */

            ToFirstChar();

            if (Peek(false) != '=')
            {
                throw new InvalidOperationException("No encoded-word available.");
            }

            StringBuilder retVal = new StringBuilder();

            while (true)
            {
                Match match = encodedword_regex.Match(m_Source, m_Offset);
                if (match.Success && match.Index == m_Offset)
                {
                    string encodedWord = m_Source.Substring(m_Offset, match.Length);
                    // Move index over encoded-word.
                    m_Offset += match.Length;

                    try{
                        if (string.Equals(match.Groups["encoding"].Value, "Q", StringComparison.InvariantCultureIgnoreCase))
                        {
                            retVal.Append(MIME_Utils.QDecode(Encoding.GetEncoding(match.Groups["charset"].Value), match.Groups["value"].Value));
                        }
                        else if (string.Equals(match.Groups["encoding"].Value, "B", StringComparison.InvariantCultureIgnoreCase))
                        {
                            retVal.Append(Encoding.GetEncoding(match.Groups["charset"].Value).GetString(Net_Utils.FromBase64(Encoding.UTF8.GetBytes(match.Groups["value"].Value))));
                        }
                        // Failed to parse encoded-word, leave it as is. RFC 2047 6.3.
                        else
                        {
                            retVal.Append(encodedWord);
                        }
                    }
                    catch {
                        // Failed to parse encoded-word, leave it as is. RFC 2047 6.3.
                        retVal.Append(encodedWord);
                    }
                }
                else
                {
                    retVal.Append(Atom());
                }

                // We have continuos encoded-word.
                match = encodedword_regex.Match(m_Source, m_Offset);
                if (match.Success && match.Index == m_Offset)
                {
                    ToFirstChar();
                }
                // encoded-word does not continue.
                else
                {
                    break;
                }
            }

            return(retVal.ToString());
        }
コード例 #5
0
        /// <summary>
        /// Parses parameters from the specified reader.
        /// </summary>
        /// <param name="reader">MIME reader.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        public void Parse(MIME_Reader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            /* RFC 2231.
             *  Asterisks ("*") are reused to provide the indicator that language and
             *  character set information is present and encoding is being used. A
             *  single quote ("'") is used to delimit the character set and language
             *  information at the beginning of the parameter value. Percent signs
             *  ("%") are used as the encoding flag, which agrees with RFC 2047.
             *
             *  Character set and language information may be combined with the
             *  parameter continuation mechanism. For example:
             *
             *  Content-Type: application/x-stuff
             *      title*0*=us-ascii'en'This%20is%20even%20more%20
             *      title*1*=%2A%2A%2Afun%2A%2A%2A%20
             *      title*2="isn't it!"
             *
             *  Note that:
             *
             *  (1) Language and character set information only appear at
             *      the beginning of a given parameter value.
             *
             *  (2) Continuations do not provide a facility for using more
             *      than one character set or language in the same
             *      parameter value.
             *
             *  (3) A value presented using multiple continuations may
             *      contain a mixture of encoded and unencoded segments.
             *
             *  (4) The first segment of a continuation MUST be encoded if
             *      language and character set information are given.
             *
             *  (5) If the first segment of a continued parameter value is
             *      encoded the language and character set field delimiters
             *      MUST be present even when the fields are left blank.
             */

            KeyValueCollection <string, _ParameterBuilder> parameters = new KeyValueCollection <string, _ParameterBuilder>();

            // Parse all parameter parts.
            string[] parameterParts = TextUtils.SplitQuotedString(reader.ToEnd(), ';');
            foreach (string part in parameterParts)
            {
                if (string.IsNullOrEmpty(part))
                {
                    continue;
                }

                string[] name_value = part.Trim().Split(new char[] { '=' }, 2);
                string   paramName  = name_value[0].Trim();
                string   paramValue = null;
                if (name_value.Length == 2)
                {
                    paramValue = TextUtils.UnQuoteString(MIME_Utils.UnfoldHeader(name_value[1].Trim()));
                }
                // Valueless parameter.
                //else{

                string[] nameParts = paramName.Split('*');
                int      index     = 0;
                bool     encoded   = nameParts.Length == 3;
                // Get multi value parameter index.
                if (nameParts.Length >= 2)
                {
                    try{
                        index = Convert.ToInt32(nameParts[1]);
                    }
                    catch {
                    }
                }

                // Single value parameter and we already have parameter with such name, skip it.
                if (nameParts.Length < 2 && parameters.ContainsKey(nameParts[0]))
                {
                    continue;
                }

                // Parameter builder doesn't exist for the specified parameter, create it.
                if (!parameters.ContainsKey(nameParts[0]))
                {
                    parameters.Add(nameParts[0], new _ParameterBuilder(nameParts[0]));
                }

                parameters[nameParts[0]].AddPart(index, encoded, paramValue);
            }

            // Build parameters from parts.
            foreach (_ParameterBuilder b in parameters)
            {
                m_pParameters.Add(b.Name, b.GetParamter());
            }

            m_IsModified = false;
        }