private IList<string> ParseGroupLists( string str, int index, int endIndex) { var groups = new List<string>(); var tokener = new Tokener(); this.Parse(str, index, endIndex, tokener); foreach (int[] token in tokener.GetTokens()) { if (token[0] == HeaderParserUtility.TokenGroup) { int startIndex = token[1]; endIndex = token[2]; string groupList = HeaderParserUtility.ParseGroupList( str, startIndex, endIndex); groupList = ParserUtility.TrimSpaceAndTab(groupList); groups.Add(groupList); } } return groups; }
/// <include file='../../docs.xml' /// path='docs/doc[@name="M:PeterO.Mail.NamedAddress.#ctor(System.String)"]/*'/> public NamedAddress(string address) { if (address == null) { throw new ArgumentNullException("address"); } var tokener = new Tokener(); if (HeaderParser.ParseAddress(address, 0, address.Length, tokener) != address.Length) { throw new ArgumentException("Address has an invalid syntax."); } NamedAddress na = HeaderParserUtility.ParseAddress( address, 0, address.Length, tokener.GetTokens()); if (na == null) { throw new ArgumentException("Address has an invalid syntax."); } this.displayName = na.displayName; this.address = na.address; this.groupAddresses = na.groupAddresses; this.isGroup = na.isGroup; }
internal static IList<NamedAddress> ParseAddresses(string value) { var tokener = new Tokener(); if (value == null) { return new List<NamedAddress>(); } // Check for valid syntax return (HeaderParser.ParseHeaderTo(value, 0, value.Length, tokener) != value.Length) ? (new List<NamedAddress>()) : HeaderParserUtility.ParseAddressList( value, 0, value.Length, tokener.GetTokens()); }
public string DecodeEncodedWords(string str) { #if DEBUG if (str == null) { throw new ArgumentNullException("str"); } #endif // For structured header fields that allow comments only wherever // whitespace // is allowed, and allow parentheses only for comments if (str.Length < 9) { // too short for encoded words return str; } if (str.IndexOf("=?", StringComparison.Ordinal) < 0) { // No encoded words return str; } var sb = new StringBuilder(); var tokener = new Tokener(); int endIndex = this.Parse(str, 0, str.Length, tokener); if (endIndex != str.Length) { // The header field is syntactically invalid, // so don't decode any encoded words // Console.WriteLine("Invalid syntax: " + this.GetType().Name + // ", " + str); return str; } var lastIndex = 0; // Get each relevant token sorted by starting index IList<int[]> tokens = tokener.GetTokens(); foreach (int[] token in tokens) { // Console.WriteLine("" + token[0] + " [" + // (str.Substring(token[1],token[2]-token[1])) + "]"); if (token[0] == HeaderParserUtility.TokenComment && token[0] >= lastIndex) { // This is a comment token int startIndex = token[1]; endIndex = token[2]; string newComment = Rfc2047.DecodeEncodedWords( str, startIndex + 1, endIndex - 1, EncodedWordContext.Comment); sb.Append(str.Substring(lastIndex, startIndex + 1 - lastIndex)); sb.Append(newComment); lastIndex = endIndex - 1; } else if (token[0] == HeaderParserUtility.TokenPhrase) { // This is a phrase token int startIndex = token[1]; endIndex = token[2]; string newComment = Rfc2047.DecodePhraseText( str, startIndex, endIndex, tokens, true); sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); sb.Append(newComment); lastIndex = endIndex; } } sb.Append(str.Substring(lastIndex, str.Length - lastIndex)); return sb.ToString(); }
public void Greater() { Assert.AreEqual(Token.Greater(), Tokener.Tokenize(">").First()); }
public void IdentifierLowerCaseOnly() { Assert.AreEqual(Token.Ident("foo"), Tokener.Tokenize("foo").First()); }
public void Equals() { Assert.AreEqual(Token.Equals(), Tokener.Tokenize("=").First()); }
public void RightBracket() { Assert.AreEqual(Token.RightBracket(), Tokener.Tokenize("]").First()); }
public void InvalidChar() { Tokener.Tokenize("what?").ToArray(); }
public void EmptyInput() { Assert.AreEqual(Token.Eoi(), Tokener.Tokenize(string.Empty).Single()); }
public void WhiteSpace() { Assert.AreEqual(Token.WhiteSpace(" \r \n \f \t "), Tokener.Tokenize(" \r \n \f \t etc").First()); }
public void SubstringMatch() { Assert.AreEqual(TokenKind.SubstringMatch, Tokener.Tokenize("*=").First().Kind); }
public void Integer() { Assert.AreEqual(Token.Integer("42"), Tokener.Tokenize("42").First()); }
public void Function() { Assert.AreEqual(Token.Function("funky"), Tokener.Tokenize("funky(").First()); }
public void BadHash() { Tokener.Tokenize("#").ToArray(); }
public string UncommentAndCollapse(string str) { var sb = new StringBuilder(); var tokener = new Tokener(); int endIndex = this.Parse(str, 0, str.Length, tokener); if (endIndex != str.Length) { // The header field is syntactically invalid return str; } var lastIndex = 0; // Get each relevant token sorted by starting index IList<int[]> tokens = tokener.GetTokens(); foreach (int[] token in tokens) { if (token[0] == HeaderParserUtility.TokenComment && token[0] >= lastIndex) { // This is a comment token; ignore the comment int startIndex = token[1]; endIndex = token[2]; sb.Append(str.Substring(lastIndex, startIndex + 1 - lastIndex)); lastIndex = endIndex - 1; } } sb.Append(str.Substring(lastIndex, str.Length - lastIndex)); string ret = sb.ToString(); ret = ParserUtility.TrimAndCollapseSpaceAndTab(ret); return ret; }
public void CommaWhiteSpacePrepended() { Assert.AreEqual(Token.Comma(), Tokener.Tokenize(" ,").First()); }
public void Star() { Assert.AreEqual(Token.Char('*'), Tokener.Tokenize("*").First()); }
public void StringSingleQuotedWithEscapedBackslashes() { Assert.AreEqual(Token.String(@"foo \bar\ baz"), Tokener.Tokenize(@"'foo \\bar\\ baz'").First()); }
public void Comma() { Assert.AreEqual(Token.Comma(), Tokener.Tokenize(",").First()); }
public void StarStar() { Assert.AreEqual(new[] { Token.Char('*'), Token.Char('*') }, Tokener.Tokenize("**").Take(2).ToArray()); }
public void Plus() { Assert.AreEqual(Token.Plus(), Tokener.Tokenize("+").First()); }
public void Tilde() { Assert.AreEqual(TokenKind.Tilde, Tokener.Tokenize("~").First().Kind); }
public void LeftBracket() { Assert.AreEqual(Token.LeftBracket(), Tokener.Tokenize("[").First()); }
public void TildeWhitespacePrepended() { Assert.AreEqual(TokenKind.Tilde, Tokener.Tokenize(" ~").First().Kind); }
public void PlusWhiteSpacePrepended() { Assert.AreEqual(Token.Plus(), Tokener.Tokenize(" +").First()); }
public void StringSingleQuoteUnterminated() { Tokener.Tokenize("'foo").ToArray(); }
public void GreaterWhiteSpacePrepended() { Assert.AreEqual(Token.Greater(), Tokener.Tokenize(" >").First()); }
public void StringDoubleQuoteUnterminated() { Tokener.Tokenize("\"foo").ToArray(); }
public void Invalid(string selector) { Assert.Throws <FormatException>(() => Parser.Parse(Tokener.Tokenize(selector), new NoSelectorGenerator())); }
public void StringInvalidEscaping() { Tokener.Tokenize(@"'f\oo").ToArray(); }
internal static IList<NamedAddress> ParseAddresses(string[] values) { var tokener = new Tokener(); var list = new List<NamedAddress>(); foreach (string addressValue in values) { if (addressValue == null) { continue; } if ( HeaderParser.ParseHeaderTo( addressValue, 0, addressValue.Length, tokener) != addressValue.Length) { // Invalid syntax continue; } list.AddRange( HeaderParserUtility.ParseAddressList( addressValue, 0, addressValue.Length, tokener.GetTokens())); } return list; }
public void NullReader() { Tokener.Tokenize((TextReader)null); }
public string DowngradeFieldValue(string str) { string originalString = str; IList<string> originalGroups = null; for (int phase = 0; phase < 5; ++phase) { if (str.IndexOf('(') < 0 && phase == 0) { // No comments in the header field value, a common case continue; } if (!Message.HasTextToEscape(str)) { // No text needs to be encoded return str; } var sb = new StringBuilder(); var tokener = new Tokener(); int endIndex = this.Parse(str, 0, str.Length, tokener); if (endIndex != str.Length) { // The header field is syntactically invalid, // so downgrading is not possible return str; } var lastIndex = 0; // Get each relevant token sorted by starting index IList<int[]> tokens = tokener.GetTokens(); var groupIndex = 0; // TODO: Received field downgrading foreach (int[] token in tokens) { if (token[1] < lastIndex) { continue; } // NOTE: Doesn't downgrade ID-Left or ID-Right // if extended characters appear in those areas switch (phase) { case 0: { // Comment downgrading if (token[0] == HeaderParserUtility.TokenComment) { int startIndex = token[1]; endIndex = token[2]; // Console.WriteLine(str.Substring(startIndex, endIndex - // startIndex)); if (Message.HasTextToEscape(str, startIndex, endIndex)) { string newComment = Rfc2047.EncodeComment( str, startIndex, endIndex); sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); sb.Append(newComment); } else { // No text needs to be escaped, output the comment as is sb.Append(str.Substring(lastIndex, endIndex - lastIndex)); } lastIndex = endIndex; } break; } case 1: { // Phrase downgrading if (token[0] == HeaderParserUtility.TokenPhrase) { int startIndex = token[1]; endIndex = token[2]; string newComment = Rfc2047.EncodePhraseText( str, startIndex, endIndex, tokens); sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); sb.Append(newComment); lastIndex = endIndex; } break; } case 2: { // Group downgrading if (token[0] == HeaderParserUtility.TokenGroup) { int startIndex = token[1]; endIndex = token[2]; var nonasciiLocalParts = false; var displayNameEnd = -1; string originalGroupList; foreach (int[] token2 in tokens) { if (token2[0] == HeaderParserUtility.TokenPhrase) { if (displayNameEnd < 0) { displayNameEnd = token2[2]; } } if (token2[0] == HeaderParserUtility.TokenLocalPart) { if (token2[1] >= startIndex && token2[2] <= endIndex) { // Local part within a group if ( Message.HasTextToEscapeIgnoreEncodedWords( str, token2[1], token2[2])) { nonasciiLocalParts = true; break; } } } } if (!nonasciiLocalParts) { int localLastIndex = startIndex; var nonasciiDomains = false; var sb2 = new StringBuilder(); foreach (int[] token2 in tokens) { if (token2[0] == HeaderParserUtility.TokenDomain) { if (token2[1] >= startIndex && token2[2] <= endIndex) { // Domain within the group string domain = HeaderParserUtility.ParseDomain( str, token2[1], token[2]); // NOTE: "domain" can include domain literals, enclosed // in brackets; they are invalid under // "IsValidDomainName" . domain = ( Message.HasTextToEscapeIgnoreEncodedWords( domain, 0, domain.Length) && Idna.IsValidDomainName( domain, false)) ? Idna.EncodeDomainName( domain) : str.Substring( token2[1], token2[2] - token2[1]); if ( Message.HasTextToEscapeIgnoreEncodedWords( domain, 0, domain.Length)) { // ASCII encoding failed nonasciiDomains = true; break; } sb2.Append( str.Substring( localLastIndex, token2[1] - localLastIndex)); sb2.Append(domain); localLastIndex = token2[2]; } } } nonasciiLocalParts = nonasciiDomains; if (!nonasciiLocalParts) { // All of the domains could be converted to ASCII sb2.Append( str.Substring( localLastIndex, endIndex - localLastIndex)); sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); sb.Append(sb2.ToString()); lastIndex = endIndex; } } if (nonasciiLocalParts) { // At least some of the domains could not // be converted to ASCII originalGroups = originalGroups ?? this.ParseGroupLists( originalString, 0, originalString.Length); originalGroupList = originalGroups[groupIndex]; string groupText = originalGroupList; string displayNameText = str.Substring( startIndex, displayNameEnd - startIndex); string encodedText = displayNameText + " " + Rfc2047.EncodeString(groupText) + " :;"; sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); sb.Append(encodedText); lastIndex = endIndex; } ++groupIndex; } break; } case 3: { // Mailbox downgrading if (token[0] == HeaderParserUtility.TokenMailbox) { int startIndex = token[1]; endIndex = token[2]; var nonasciiLocalPart = false; var hasPhrase = false; foreach (int[] token2 in tokens) { hasPhrase |= token2[0] == HeaderParserUtility.TokenPhrase; if (token2[0] == HeaderParserUtility.TokenLocalPart) { if (token2[1] >= startIndex && token2[2] <= endIndex) { if ( Message.HasTextToEscapeIgnoreEncodedWords( str, token2[1], token2[2])) { nonasciiLocalPart = true; break; } } } } if (!nonasciiLocalPart) { int localLastIndex = startIndex; var nonasciiDomains = false; var sb2 = new StringBuilder(); foreach (int[] token2 in tokens) { if (token2[0] == HeaderParserUtility.TokenDomain) { if (token2[1] >= startIndex && token2[2] <= endIndex) { // Domain within the group string domain = HeaderParserUtility.ParseDomain( str, token2[1], token[2]); // NOTE: "domain" can include domain literals, enclosed // in brackets; they are invalid under // "IsValidDomainName" . domain = ( Message.HasTextToEscapeIgnoreEncodedWords( domain, 0, domain.Length) && Idna.IsValidDomainName( domain, false)) ? Idna.EncodeDomainName( domain) : str.Substring( token2[1], token2[2] - token2[1]); if ( Message.HasTextToEscapeIgnoreEncodedWords( domain, 0, domain.Length)) { // ASCII encoding failed nonasciiDomains = true; break; } sb2.Append( str.Substring( localLastIndex, token2[1] - localLastIndex)); sb2.Append(domain); localLastIndex = token2[2]; } } } nonasciiLocalPart = nonasciiDomains; if (!nonasciiLocalPart) { // All of the domains could be converted to ASCII sb2.Append( str.Substring( localLastIndex, endIndex - localLastIndex)); sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); sb.Append(sb2.ToString()); lastIndex = endIndex; } } // Downgrading failed if (nonasciiLocalPart) { sb.Append(str.Substring(lastIndex, startIndex - lastIndex)); if (!hasPhrase) { string addrSpec = str.Substring( token[1], token[2] - token[1]); string encodedText = " " + Rfc2047.EncodeString(addrSpec) + " :;"; sb.Append(encodedText); } else { // Has a phrase, extract the addr-spec and convert // the mailbox to a group int angleAddrStart = HeaderParser.ParsePhrase( str, token[1], token[2], null); // append the rest of the string so far up to and // including the phrase sb.Append( str.Substring( lastIndex, angleAddrStart - lastIndex)); int addrSpecStart = HeaderParser.ParseCFWS( str, angleAddrStart, token[2], null); if (addrSpecStart < token[2] && str[addrSpecStart] == '<') { ++addrSpecStart; } addrSpecStart = HeaderParser.ParseObsRoute( str, addrSpecStart, token[2], null); int addrSpecEnd = HeaderParser.ParseAddrSpec( str, addrSpecStart, token[2], null); string addrSpec = str.Substring( addrSpecStart, addrSpecEnd - addrSpecStart); string valueSbString = sb.ToString(); bool endsWithSpace = sb.Length > 0 && (valueSbString[valueSbString.Length - 1] == 0x20 || valueSbString[valueSbString.Length - 1] == 0x09); string encodedText = (endsWithSpace ? String.Empty : " ") + Rfc2047.EncodeString(addrSpec) + " :;"; sb.Append(encodedText); } lastIndex = endIndex; } ++groupIndex; } break; } } } sb.Append(str.Substring(lastIndex, str.Length - lastIndex)); str = sb.ToString(); } return str; }
public void Colon() { Assert.AreEqual(Token.Colon(), Tokener.Tokenize(":").First()); }
public void RightParenthesis() { Assert.AreEqual(Token.RightParenthesis(), Tokener.Tokenize(")").First()); }
public void StringReader() { Assert.AreEqual(new[] { Token.Integer("123"), Token.Comma(), Token.Char('*'), Token.Eoi() }, Tokener.Tokenize(new StringReader("123,*")).ToArray()); }