Example #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.Default.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);
            }
        }
        /// <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);
        }
Example #3
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.Default.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());
        }
        /// <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.Default.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);
        }