/// <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> /// 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> /// 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> /// 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> /// 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 Mail-Parameters from the tokens. /// </summary> /// <param name="enumerator">The enumerator to perform the make on.</param> /// <param name="parameters">The mail parameters that were made.</param> /// <returns>true if the mail parameters can be made, false if not.</returns> /// <remarks><![CDATA[esmtp-param *(SP esmtp-param)]]></remarks> public bool TryMakeMailParameters(TokenEnumerator enumerator, out IDictionary <string, string> parameters) { parameters = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); while (enumerator.Peek().Kind != TokenKind.None) { KeyValuePair <string, string> parameter; if (TryMake(enumerator, TryMakeEsmtpParameter, out parameter) == false) { return(false); } parameters.Add(parameter); enumerator.TakeWhile(t => t.Kind == TokenKind.Space); } return(parameters.Count > 0); }
/// <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> /// 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 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); }