/// <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(Mimes.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.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> /// 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(Mimes.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.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()); }