/// <summary> /// Make a RCTP command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The RCTP command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeRcpt(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "RCPT")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); if (enumerator.Take() != new Token(TokenKind.Text, "TO") || enumerator.Take() != new Token(TokenKind.Punctuation, ":")) { errorResponse = new SmtpResponse(SmtpReplyCode.SyntaxError, "missing the TO:"); return(false); } // according to the spec, whitespace isnt allowed here anyway enumerator.TakeWhile(TokenKind.Space); IMailbox mailbox; if (_parser.TryMakePath(enumerator, out mailbox) == false) { _logger.LogVerbose("Syntax Error (Text={0})", enumerator.AsText()); errorResponse = SmtpResponse.SyntaxError; return(false); } // TODO: support optional service extension parameters here command = new RcptCommand(mailbox, _options.MailboxFilterFactory); return(true); }
/// <summary> /// Try to make a address. /// </summary> /// <param name="enumerator">The enumerator to make the address from.</param> /// <param name="address">The address that was made, or undefined if it was not made.</param> /// <returns>true if the address was made, false if not.</returns> /// <remarks><![CDATA["[" ( IPv4-address-literal / IPv6-address-literal / General-address-literal ) "]"]]></remarks> public bool TryMakeAddressLiteral(TokenEnumerator enumerator, out string address) { address = null; if (enumerator.Take() != new Token(TokenKind.Punctuation, "[")) { return(false); } // skip any whitespace enumerator.TakeWhile(t => t.Kind == TokenKind.Space); if (TryMake(enumerator, TryMakeIpv4AddressLiteral, out address) == false) { return(false); } // skip any whitespace enumerator.TakeWhile(t => t.Kind == TokenKind.Space); if (enumerator.Take() != new Token(TokenKind.Punctuation, "]")) { return(false); } return(address != null); }
/// <summary> /// Try to make a path. /// </summary> /// <param name="enumerator">The enumerator to make the path from.</param> /// <param name="mailbox">The path that was made, or undefined if it was not made.</param> /// <returns>true if the path was made, false if not.</returns> /// <remarks><![CDATA["<" [ A-d-l ":" ] Mailbox ">"]]></remarks> public bool TryMakePath(TokenEnumerator enumerator, out IMailbox mailbox) { mailbox = null; if (enumerator.Take() != new Token(TokenKind.Symbol, "<")) { return(false); } // Note, the at-domain-list must be matched, but also must be ignored // http://tools.ietf.org/html/rfc5321#appendix-C string atDomainList; if (TryMake(enumerator, TryMakeAtDomainList, out atDomainList)) { // if the @domain list was matched then it needs to be followed by a colon if (enumerator.Take() != new Token(TokenKind.Punctuation, ":")) { return(false); } } if (TryMake(enumerator, TryMakeMailbox, out mailbox) == false) { return(false); } return(enumerator.Take() == new Token(TokenKind.Symbol, ">")); }
/// <summary> /// Make an AUTH command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The AUTH command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeAuth(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "AUTH")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); AuthenticationMethod method; if (Enum.TryParse(enumerator.Peek().Text, true, out method) == false) { _logger.LogVerbose("AUTH command requires a valid method (PLAIN or LOGIN)"); errorResponse = SmtpResponse.SyntaxError; return(false); } enumerator.Take(); string parameter = null; if (enumerator.Count > 0 && _parser.TryMakeBase64(enumerator, out parameter) == false) { _logger.LogVerbose("AUTH parameter must be a Base64 encoded string"); errorResponse = SmtpResponse.SyntaxError; return(false); } command = new AuthCommand(_options.UserAuthenticator, method, parameter); return(true); }
/// <summary> /// Try to make a quoted pair from the tokens. /// </summary> /// <param name="enumerator">The enumerator to make the text from.</param> /// <param name="text">The text that was made.</param> /// <returns>true if the quoted pair was made, false if not.</returns> /// <remarks><![CDATA[%d92 %d32-126]]></remarks> public bool TryMakeQuotedPairSmtp(TokenEnumerator enumerator, out string text) { text = null; if (enumerator.Take() != new Token(TokenKind.Punctuation, '\\')) { return(false); } text += enumerator.Take().Text; return(true); }
/// <summary> /// Try to make an IPv4 address literal. /// </summary> /// <param name="enumerator">The enumerator to make the address from.</param> /// <param name="address">The address that was made, or undefined if it was not made.</param> /// <returns>true if the address was made, false if not.</returns> /// <remarks><![CDATA[ Snum 3("." Snum) ]]></remarks> public bool TryMakeIpv4AddressLiteral(TokenEnumerator enumerator, out string address) { address = null; int snum; if (TryMake(enumerator, TryMakeSnum, out snum) == false) { return(false); } address = snum.ToString(CultureInfo.InvariantCulture); for (var i = 0; i < 3 && enumerator.Peek() == new Token(TokenKind.Punctuation, "."); i++) { enumerator.Take(); if (TryMake(enumerator, TryMakeSnum, out snum) == false) { return(false); } address = String.Concat(address, '.', snum); } return(true); }
/// <summary> /// Try to make the allowable characters in a base64 encoded string. /// </summary> /// <param name="enumerator">The enumerator to perform the make on.</param> /// <param name="base64Chars">The base64 characters that were found.</param> /// <returns>true if the base64-chars can be made, false if not.</returns> /// <remarks><![CDATA[ALPHA / DIGIT / "+" / "/"]]></remarks> static bool TryMakeBase64Chars(TokenEnumerator enumerator, out string base64Chars) { base64Chars = null; var token = enumerator.Take(); switch (token.Kind) { case TokenKind.Text: case TokenKind.Number: base64Chars = token.Text; return(true); case TokenKind.Punctuation: switch (token.Text[0]) { case '/': base64Chars = token.Text; return(true); } break; case TokenKind.Symbol: switch (token.Text[0]) { case '+': base64Chars = token.Text; return(true); } break; } return(false); }
/// <summary> /// Try to make an Esmtp-Parameter from the tokens. /// </summary> /// <param name="enumerator">The enumerator to perform the make on.</param> /// <param name="parameter">The esmtp-parameter that was made.</param> /// <returns>true if the esmtp-parameter can be made, false if not.</returns> /// <remarks><![CDATA[esmtp-keyword ["=" esmtp-value]]]></remarks> public bool TryMakeEsmtpParameter(TokenEnumerator enumerator, out KeyValuePair <string, string> parameter) { parameter = default(KeyValuePair <string, string>); string keyword; if (TryMake(enumerator, TryMakeEsmtpKeyword, out keyword) == false) { return(false); } if (enumerator.Take() != new Token(TokenKind.Symbol, "=")) { return(false); } string value; if (TryMake(enumerator, TryMakeEsmtpValue, out value) == false) { return(false); } parameter = new KeyValuePair <string, string>(keyword, value); return(true); }
/// <summary> /// Try to make a QTextSMTP from the tokens. /// </summary> /// <param name="enumerator">The enumerator to make the text from.</param> /// <param name="text">The text that was made.</param> /// <returns>true if the quoted text was made, false if not.</returns> /// <remarks><![CDATA[%d32-33 / %d35-91 / %d93-126]]></remarks> public bool TryMakeQTextSmtp(TokenEnumerator enumerator, out string text) { text = null; var token = enumerator.Take(); switch (token.Kind) { case TokenKind.Text: case TokenKind.Space: case TokenKind.Number: case TokenKind.Symbol: text += token.Text; return(true); case TokenKind.Punctuation: if (token.Text[0] == '"' || token.Text[0] == '\\') { return(false); } text += token.Text; return(true); } return(false); }
/// <summary> /// Make an EHLO command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The EHLO command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeEhlo(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "EHLO")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); string domain; if (_parser.TryMakeDomain(enumerator, out domain)) { command = new EhloCommand(domain, _options); return(true); } string address; if (_parser.TryMakeAddressLiteral(enumerator, out address)) { command = new EhloCommand(address, _options); return(true); } errorResponse = SmtpResponse.SyntaxError; return(false); }
/// <summary> /// Try to make a text or number /// </summary> /// <param name="enumerator">The enumerator to make a text or number from.</param> /// <param name="textOrNumber">The text or number that was made, or undefined if it was not made.</param> /// <returns>true if the text or number was made, false if not.</returns> /// <remarks><![CDATA[ALPHA / DIGIT]]></remarks> public bool TryMakeTextOrNumber(TokenEnumerator enumerator, out string textOrNumber) { var token = enumerator.Take(); textOrNumber = token.Text; return(token.Kind == TokenKind.Text || token.Kind == TokenKind.Number); }
public void EnumerateTokens() { var tokenizer = new TokenEnumerator(new ByteArrayTokenReader(Segments)); while (tokenizer.Peek() != Token.None) { tokenizer.Take(); } }
/// <summary> /// Make a MAIL command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The MAIL command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeMail(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "MAIL")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); if (enumerator.Take() != new Token(TokenKind.Text, "FROM") || enumerator.Take() != new Token(TokenKind.Punctuation, ":")) { errorResponse = new SmtpResponse(SmtpReplyCode.SyntaxError, "missing the FROM:"); return(false); } // according to the spec, whitespace isnt allowed here but most servers send it enumerator.TakeWhile(TokenKind.Space); IMailbox mailbox; if (_parser.TryMakeReversePath(enumerator, out mailbox) == false) { _logger.LogVerbose("Syntax Error (Text={0})", enumerator.AsText()); errorResponse = new SmtpResponse(SmtpReplyCode.SyntaxError); return(false); } enumerator.TakeWhile(TokenKind.Space); // match the optional (ESMTP) parameters IReadOnlyDictionary <string, string> parameters; if (_parser.TryMakeMailParameters(enumerator, out parameters) == false) { parameters = new Dictionary <string, string>(); } command = new MailCommand(_options, mailbox, parameters); return(true); }
/// <summary> /// Try to make an Snum (number in the range of 0-255). /// </summary> /// <param name="enumerator">The enumerator to make the address from.</param> /// <param name="snum">The snum that was made, or undefined if it was not made.</param> /// <returns>true if the snum was made, false if not.</returns> /// <remarks><![CDATA[ 1*3DIGIT ]]></remarks> public bool TryMakeSnum(TokenEnumerator enumerator, out int snum) { var token = enumerator.Take(); if (Int32.TryParse(token.Text, out snum) && token.Kind == TokenKind.Number) { return(snum >= 0 && snum <= 255); } return(false); }
/// <summary> /// Try to make a quoted-string from the tokens. /// </summary> /// <param name="enumerator">The enumerator to make the quoted-string from.</param> /// <param name="quotedString">The quoted-string that was made, or undefined if it was not made.</param> /// <returns>true if the quoted-string was made, false if not.</returns> /// <remarks><![CDATA[DQUOTE * QcontentSMTP DQUOTE]]></remarks> public bool TryMakeQuotedString(TokenEnumerator enumerator, out string quotedString) { quotedString = null; if (enumerator.Take() != new Token(TokenKind.Punctuation, "\"")) { return(false); } while (enumerator.Peek() != new Token(TokenKind.Punctuation, "\"")) { string text; if (TryMakeQContentSmtp(enumerator, out text) == false) { return(false); } quotedString += text; } return(enumerator.Take() == new Token(TokenKind.Punctuation, "\"")); }
/// <summary> /// Try to make an "Atext" from the tokens. /// </summary> /// <param name="enumerator">The enumerator to make the atext from.</param> /// <param name="atext">The atext that was made, or undefined if it was not made.</param> /// <returns>true if the atext was made, false if not.</returns> /// <remarks><![CDATA[atext]]></remarks> public bool TryMakeAtext(TokenEnumerator enumerator, out string atext) { atext = null; var token = enumerator.Take(); switch (token.Kind) { case TokenKind.Text: case TokenKind.Number: atext = token.Text; return(true); case TokenKind.Punctuation: switch (token.Text[0]) { case '!': case '#': case '%': case '&': case '\'': case '*': case '-': case '/': case '?': case '_': case '{': case '}': atext = token.Text; return(true); } break; case TokenKind.Symbol: switch (token.Text[0]) { case '$': case '+': case '=': case '^': case '`': case '|': case '~': atext = token.Text; return(true); } break; } return(false); }
/// <summary> /// Try to make an Esmtp-Value from the tokens. /// </summary> /// <param name="enumerator">The enumerator to perform the make on.</param> /// <param name="value">The esmtp-value that was made.</param> /// <returns>true if the esmtp-value can be made, false if not.</returns> /// <remarks><![CDATA[1*(%d33-60 / %d62-127)]]></remarks> public bool TryMakeEsmtpValue(TokenEnumerator enumerator, out string value) { value = null; var token = enumerator.Peek(); while (token.Text.Length > 0 && token.Text.ToCharArray().All(ch => (ch >= 33 && ch <= 66) || (ch >= 62 && ch <= 127))) { value += enumerator.Take().Text; token = enumerator.Peek(); } return(value != null); }
/// <summary> /// Try to make an Esmtp-Keyword from the tokens. /// </summary> /// <param name="enumerator">The enumerator to perform the make on.</param> /// <param name="keyword">The esmtp-keyword that was made.</param> /// <returns>true if the esmtp-keyword can be made, false if not.</returns> /// <remarks><![CDATA[(ALPHA / DIGIT) *(ALPHA / DIGIT / "-")]]></remarks> public bool TryMakeEsmtpKeyword(TokenEnumerator enumerator, out string keyword) { keyword = null; var token = enumerator.Peek(); while (token.Kind == TokenKind.Text || token.Kind == TokenKind.Number || token == new Token(TokenKind.Punctuation, "-")) { keyword += enumerator.Take().Text; token = enumerator.Peek(); } return(keyword != null); }
/// <summary> /// Try to make a reverse path. /// </summary> /// <param name="enumerator">The enumerator to make the reverse path from.</param> /// <param name="mailbox">The reverse path that was made, or undefined if it was not made.</param> /// <returns>true if the reverse path was made, false if not.</returns> /// <remarks><![CDATA[Path / "<>"]]></remarks> public bool TryMakeReversePath(TokenEnumerator enumerator, out IMailbox mailbox) { if (TryMake(enumerator, TryMakePath, out mailbox)) { return(true); } if (enumerator.Take() != new Token(TokenKind.Symbol, "<")) { return(false); } // not valid according to the spec but some senders do it enumerator.TakeWhile(t => t.Kind == TokenKind.Space); if (enumerator.Take() != new Token(TokenKind.Symbol, ">")) { return(false); } mailbox = null; return(true); }
/// <summary> /// Try to make a text/number/hyphen string. /// </summary> /// <param name="enumerator">The enumerator to make the text/number/hyphen from.</param> /// <param name="textOrNumberOrHyphenString">The text, number, or hyphen that was matched, or undefined if it was not matched.</param> /// <returns>true if a text, number or hyphen was made, false if not.</returns> /// <remarks><![CDATA[*( ALPHA / DIGIT / "-" ) Let-dig]]></remarks> public bool TryMakeTextOrNumberOrHyphenString(TokenEnumerator enumerator, out string textOrNumberOrHyphenString) { textOrNumberOrHyphenString = null; var token = enumerator.Peek(); while (token.Kind == TokenKind.Text || token.Kind == TokenKind.Number || token == new Token(TokenKind.Punctuation, "-")) { textOrNumberOrHyphenString += enumerator.Take().Text; token = enumerator.Peek(); } // can not end with a hyphen return(textOrNumberOrHyphenString != null && token != new Token(TokenKind.Punctuation, "-")); }
/// <summary> /// Try to make an @domain. /// </summary> /// <param name="enumerator">The enumerator to make the @domain from.</param> /// <param name="atDomain">The @domain that was made, or undefined if it was not made.</param> /// <returns>true if the @domain was made, false if not.</returns> /// <remarks><![CDATA["@" Domain]]></remarks> public bool TryMakeAtDomain(TokenEnumerator enumerator, out string atDomain) { atDomain = null; if (enumerator.Take() != new Token(TokenKind.Punctuation, "@")) { return(false); } string domain; if (TryMake(enumerator, TryMakeDomain, out domain) == false) { return(false); } atDomain = String.Format("@{0}", domain); return(true); }
/// <summary> /// Make an RSET command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The RSET command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeRset(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "RSET")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); if (enumerator.Count > 1) { _logger.LogVerbose("RSET command can not have parameters (found {0} parameters).", enumerator.Count); errorResponse = SmtpResponse.SyntaxError; return(false); } command = RsetCommand.Instance; return(true); }
/// <summary> /// Make an STARTTLS command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The STARTTLS command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeStartTls(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "STARTTLS")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); if (enumerator.Count > 1) { _logger.LogVerbose("STARTTLS command can not have parameters (Tokens={0})", enumerator.Count); errorResponse = SmtpResponse.SyntaxError; return(false); } command = new StartTlsCommand(_options.ServerCertificate); return(true); }
/// <summary> /// Make a DATA command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The DATA command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeData(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "DATA")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); if (enumerator.Count > 1) { _logger.LogVerbose("DATA command can not have parameters (Tokens={0})", enumerator.Count); errorResponse = SmtpResponse.SyntaxError; return(false); } command = new DataCommand(_options.MessageStoreFactory); return(true); }
/// <summary> /// Try to make a domain name. /// </summary> /// <param name="enumerator">The enumerator to make the domain name from.</param> /// <param name="domain">The domain name that was made, or undefined if it was not made.</param> /// <returns>true if the domain name was made, false if not.</returns> /// <remarks><![CDATA[sub-domain *("." sub-domain)]]></remarks> public bool TryMakeDomain(TokenEnumerator enumerator, out string domain) { if (TryMake(enumerator, TryMakeSubdomain, out domain) == false) { return(false); } while (enumerator.Peek() == new Token(TokenKind.Punctuation, ".")) { enumerator.Take(); string subdomain; if (TryMake(enumerator, TryMakeSubdomain, out subdomain) == false) { return(false); } domain += String.Concat(".", subdomain); } return(true); }
/// <summary> /// Try to make a dot-string from the tokens. /// </summary> /// <param name="enumerator">The enumerator to make the dot-string from.</param> /// <param name="dotString">The dot-string that was made, or undefined if it was not made.</param> /// <returns>true if the dot-string was made, false if not.</returns> /// <remarks><![CDATA[Atom *("." Atom)]]></remarks> public bool TryMakeDotString(TokenEnumerator enumerator, out string dotString) { if (TryMake(enumerator, TryMakeAtom, out dotString) == false) { return(false); } while (enumerator.Peek() == new Token(TokenKind.Punctuation, ".")) { // skip the punctuation enumerator.Take(); string atom; if (TryMake(enumerator, TryMakeAtom, out atom) == false) { return(true); } dotString += String.Concat(".", atom); } return(true); }
/// <summary> /// Try to make an @domain list. /// </summary> /// <param name="enumerator">The enumerator to make the @domain list from.</param> /// <param name="atDomainList">The @domain list that was made, or undefined if it was not made.</param> /// <returns>true if the @domain list was made, false if not.</returns> /// <remarks><![CDATA[At-domain *( "," At-domain )]]></remarks> public bool TryMakeAtDomainList(TokenEnumerator enumerator, out string atDomainList) { if (TryMake(enumerator, TryMakeAtDomain, out atDomainList) == false) { return(false); } // match the optional list while (enumerator.Peek() == new Token(TokenKind.Punctuation, ",")) { enumerator.Take(); string atDomain; if (TryMake(enumerator, TryMakeAtDomain, out atDomain) == false) { return(false); } atDomainList += String.Format(",{0}", atDomain); } return(true); }
/// <summary> /// Make a HELO command from the given enumerator. /// </summary> /// <param name="enumerator">The enumerator to create the command from.</param> /// <param name="command">The HELO command that is defined within the token enumerator.</param> /// <param name="errorResponse">The error that indicates why the command could not be made.</param> /// <returns>Returns true if a command could be made, false if not.</returns> public bool TryMakeHelo(TokenEnumerator enumerator, out SmtpCommand command, out SmtpResponse errorResponse) { Debug.Assert(enumerator.Peek() == new Token(TokenKind.Text, "HELO")); command = null; errorResponse = null; enumerator.Take(); enumerator.TakeWhile(TokenKind.Space); string domain; if (_parser.TryMakeDomain(enumerator, out domain) == false) { _logger.LogVerbose("Could not match the domain name (Text={0}).", enumerator.AsText()); errorResponse = SmtpResponse.SyntaxError; return(false); } command = new HeloCommand(domain); return(true); }
/// <summary> /// Try to make a mailbox. /// </summary> /// <param name="enumerator">The enumerator to make the mailbox from.</param> /// <param name="mailbox">The mailbox that was made, or undefined if it was not made.</param> /// <returns>true if the mailbox was made, false if not.</returns> /// <remarks><![CDATA[Local-part "@" ( Domain / address-literal )]]></remarks> public bool TryMakeMailbox(TokenEnumerator enumerator, out IMailbox mailbox) { mailbox = null; string localpart; if (TryMake(enumerator, TryMakeLocalPart, out localpart) == false) { return(false); } if (enumerator.Take() != new Token(TokenKind.Punctuation, "@")) { return(false); } string domain; if (TryMake(enumerator, TryMakeDomain, out domain)) { mailbox = new Mailbox(localpart, domain); return(true); } string address; if (TryMake(enumerator, TryMakeAddressLiteral, out address)) { mailbox = new Mailbox(localpart, address); return(true); } return(false); }