public void GetVerb_SupportedCommands_ReturnProperVerb() { // Arrange var testCommands = new KeyValuePair <string, SmtpVerb>[] { new KeyValuePair <string, SmtpVerb>("HELO", SmtpVerb.Hello), new KeyValuePair <string, SmtpVerb>("EHLO", SmtpVerb.ExtendedHello), new KeyValuePair <string, SmtpVerb>("MAIL", SmtpVerb.Mail), new KeyValuePair <string, SmtpVerb>("RCPT", SmtpVerb.Recipient), new KeyValuePair <string, SmtpVerb>("DATA", SmtpVerb.Data), new KeyValuePair <string, SmtpVerb>("RSET", SmtpVerb.Reset), new KeyValuePair <string, SmtpVerb>("VRFY", SmtpVerb.Verify), new KeyValuePair <string, SmtpVerb>("EXPN", SmtpVerb.Expand), new KeyValuePair <string, SmtpVerb>("HELP", SmtpVerb.Help), new KeyValuePair <string, SmtpVerb>("NOOP", SmtpVerb.NoOp), new KeyValuePair <string, SmtpVerb>("QUIT", SmtpVerb.Quit), }; foreach (var commandPair in testCommands) { // Act var resultingVerb = SmtpCommand.GetVerb(commandPair.Key); // Assert Assert.AreEqual(commandPair.Value, resultingVerb, string.Format("Command string {0} did not return verb {1}", commandPair.Key, commandPair.Value)); } }
public void Parsing_ArgsSeparatedByColon() { SmtpCommand command = new SmtpCommand("DATA:ARGS"); Assert.True(command.IsValid); Assert.Equal("DATA", command.Verb); Assert.Equal("ARGS", command.ArgumentsText); }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { X509Certificate certificate = connection.Server.Behaviour.GetSSLCertificate(connection); if (certificate == null) { await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.CommandNotImplemented, "TLS configuration error - no certificate")); return; } await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.ServiceReady, "Ready to start TLS")); #pragma warning disable 0618 var sslProtos = SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls; #pragma warning restore 0618 await connection.ApplyStreamFilterAsync(async stream => { SslStream sslStream = new SslStream(stream); await sslStream.AuthenticateAsServerAsync(certificate , false, sslProtos, false); return sslStream; }); connection.Session.SecureConnection = true; }
public void Parsing_SingleToken() { SmtpCommand command = new SmtpCommand("DATA"); Assert.True(command.IsValid); Assert.Equal("DATA", command.Verb); Assert.Equal("", command.ArgumentsText); }
public void Parsing_ArgsSeparatedByColon() { var command = new SmtpCommand("DATA:ARGS"); Assert.True(command.IsValid); Assert.Equal("DATA", command.Verb); Assert.Equal("ARGS", command.ArgumentsText); }
public void Parsing_ArgsSeparatedBySpace() { SmtpCommand command = new SmtpCommand("DATA ARGS"); Assert.IsTrue(command.IsValid); Assert.AreEqual("DATA", command.Verb); Assert.AreEqual("ARGS", command.ArgumentsText); }
public void Parsing_SingleToken() { var command = new SmtpCommand("DATA"); Assert.True(command.IsValid); Assert.Equal("DATA", command.Verb); Assert.Equal("", command.ArgumentsText); }
public void Parsing_SingleToken() { SmtpCommand command = new SmtpCommand("DATA"); Assert.IsTrue(command.IsValid); Assert.AreEqual("DATA", command.Verb); Assert.AreEqual("", command.ArgumentsText); Assert.AreEqual(0, command.Arguments.Length); }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.ClosingTransmissionChannel, "Goodbye")); await connection.CloseConnectionAsync(); connection.Session.CompletedNormally = true; }
private void CheckDataForCommand(string dataRead) { var parseResult = SmtpCommand.Parse(dataRead); if (parseResult.Success) { LastCommand = parseResult.Result; } }
/// <summary> /// Execute the command. /// </summary> /// <param name="command">The command to execute.</param> /// <param name="context">The execution context to operate on.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A task which asynchronously performs the execution.</returns> static async Task <bool> ExecuteAsync(SmtpCommand command, SmtpSessionContext context, CancellationToken cancellationToken) { context.RaiseCommandExecuting(command); var result = await command.ExecuteAsync(context, cancellationToken); context.RaiseCommandExecuted(command); return(result); }
public void Parsing_MailFrom_WithDisplayName() { SmtpCommand command = new SmtpCommand("MAIL FROM:<Robert Wood<*****@*****.**>> ARG1 ARG2"); Assert.IsTrue(command.IsValid); Assert.AreEqual("MAIL", command.Verb); Assert.AreEqual("FROM:<Robert Wood<*****@*****.**>> ARG1 ARG2", command.ArgumentsText); Assert.AreEqual("FROM", command.Arguments[0]); Assert.AreEqual("<Robert Wood<*****@*****.**>>", command.Arguments[1]); Assert.AreEqual("ARG1", command.Arguments[2]); Assert.AreEqual("ARG2", command.Arguments[3]); }
public void Parsing_MailFrom_EmailOnly() { SmtpCommand command = new SmtpCommand("MAIL FROM:<*****@*****.**> ARG1 ARG2"); Assert.IsTrue(command.IsValid); Assert.AreEqual("MAIL", command.Verb); Assert.AreEqual("FROM:<*****@*****.**> ARG1 ARG2", command.ArgumentsText); Assert.AreEqual("FROM", command.Arguments[0]); Assert.AreEqual("<*****@*****.**>", command.Arguments[1]); Assert.AreEqual("ARG1", command.Arguments[2]); Assert.AreEqual("ARG2", command.Arguments[3]); }
void QueueCommand(SmtpCommand type, string command) { if (queue == null) { queue = new MemoryBlockStream(); } var bytes = Encoding.UTF8.GetBytes(command + "\r\n"); queue.Write(bytes, 0, bytes.Length); queued.Add(type); }
public void Parse_EHLOWithoutDomain_ReturnsTrueWithNoArguments() { // Arrange var testCommand = "EHLO SP"; // Act var result = SmtpCommand.Parse(testCommand); // Assert Assert.IsTrue(result.Success); Assert.IsFalse(result.Result.Arguments.Any()); }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { if (!string.IsNullOrEmpty(connection.Session.ClientName)) { await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.BadSequenceOfCommands, "You already said HELO")); return; } connection.Session.ClientName = command.ArgumentsText ?? ""; await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.Ok, "Nice to meet you")); }
private void CheckExpectedToken(byte[] token) { this.TrimStart(); if (token.Length >= this.RemainingBufferLength) { throw new FormatException("Expected token is missing"); } if (!SmtpCommand.CompareArg(token, this.commandBytes, this.currentOffset, token.Length)) { throw new FormatException("Expected token is missing"); } this.currentOffset += token.Length; }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { if (connection.CurrentMessage != null) { await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.BadSequenceOfCommands, "You already told me who the message was from")); return; } if (command.ArgumentsText.Length == 0) { await connection.WriteResponseAsync( new SmtpResponse(StandardSmtpResponseCode.SyntaxErrorInCommandArguments, "Must specify from address or <>")); return; } var argumentsParser = new ArgumentsParser(command.ArgumentsText); var arguments = argumentsParser.Arguments; var from = arguments.First(); if (from.StartsWith("<")) { from = from.Remove(0, 1); } if (from.EndsWith(">")) { from = from.Remove(from.Length - 1, 1); } connection.Server.Behaviour.OnMessageStart(connection, from); connection.NewMessage(); connection.CurrentMessage.ReceivedDate = _currentDateTimeProvider.GetCurrentDateTime(); connection.CurrentMessage.From = from; try { await ParameterProcessorMap.ProcessAsync(connection, arguments.Skip(1).ToArray(), true); await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.Ok, "New message started")); } catch { connection.AbortMessage(); throw; } }
/// <summary> /// Try to accept the command given the current state. /// </summary> /// <param name="command">The command to accept.</param> /// <param name="errorResponse">The error response to display if the command was not accepted.</param> /// <returns>true if the command could be accepted, false if not.</returns> public bool TryAccept(SmtpCommand command, out SmtpResponse errorResponse) { errorResponse = null; if (_state.Transitions.TryGetValue(command.Name, out var transition) == false || transition.CanAccept(_context) == false) { var commands = _state.Transitions.Where(t => t.Value.CanAccept(_context)).Select(t => t.Key); errorResponse = new SmtpResponse(SmtpReplyCode.SyntaxError, $"expected {string.Join("/", commands)}"); return(false); } _transition = transition; return(true); }
public override async Task ProcessAsync(IConnection connection, SmtpCommand command) { if (connection.CurrentMessage != null && connection.CurrentMessage.EightBitTransport) { connection.SetReaderEncoding(Encoding.UTF8); } try { await base.ProcessAsync(connection, command); } finally { connection.SetReaderEncodingToDefault(); } }
public async virtual Task ProcessAsync(IConnection connection, SmtpCommand command) { SmtpCommand subrequest = new SmtpCommand(command.ArgumentsText); IVerb verbProcessor = SubVerbMap.GetVerbProcessor(subrequest.Verb); if (verbProcessor != null) { await verbProcessor.ProcessAsync(connection, subrequest); } else { await connection.WriteResponseAsync( new SmtpResponse(StandardSmtpResponseCode.CommandParameterNotImplemented, "Subcommand {0} not implemented", subrequest.Verb)); } }
public async override Task ProcessAsync(IConnection connection, SmtpCommand command) { if (connection.CurrentMessage != null && connection.CurrentMessage.EightBitTransport) { connection.SetReaderEncoding(Encoding.UTF8); } try { await base.ProcessAsync(connection, command); } finally { connection.SetReaderEncodingToDefault(); } }
public virtual async Task ProcessAsync(IConnection connection, SmtpCommand command) { var subrequest = new SmtpCommand(command.ArgumentsText); var verbProcessor = SubVerbMap.GetVerbProcessor(subrequest.Verb); if (verbProcessor != null) { await verbProcessor.ProcessAsync(connection, subrequest); } else { await connection.WriteResponseAsync( new SmtpResponse(StandardSmtpResponseCode.CommandParameterNotImplemented, "Subcommand {0} not implemented", subrequest.Verb)); } }
public virtual void Process(IConnection connection, SmtpCommand command) { SmtpCommand subrequest = new SmtpCommand(command.ArgumentsText); IVerb verbProcessor = SubVerbMap.GetVerbProcessor(subrequest.Verb); if (verbProcessor != null) { verbProcessor.Process(connection, subrequest); } else { connection.WriteResponse( new SmtpResponse(StandardSmtpResponseCode.CommandParameterNotImplemented, "Subcommand {0} not implemented", subrequest.Verb)); } }
public override void Process(IConnection connection, SmtpCommand command) { if (connection.CurrentMessage != null && connection.CurrentMessage.EightBitTransport) { connection.SetReaderEncoding(Encoding.Default); } try { base.Process(connection, command); } finally { connection.SetReaderEncodingToDefault(); } }
public void Process(IConnection connection, SmtpCommand command) { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.ServiceReady, "Ready to start TLS")); connection.ApplyStreamFilter(stream => { SslStream sslStream = new SslStream(stream); sslStream.AuthenticateAsServer( connection.Server.Behaviour.GetSSLCertificate( connection), false, SslProtocols.None, false); return(sslStream); }); connection.Session.SecureConnection = true; }
public void ParseArguments_FromArgument_ReturnsArgumentPair() { // Arrange var testCommandParts = new string[] { "TEST", "FROM:[email protected]" }; // Act var result = SmtpCommand.ParseArguments(testCommandParts); // Assert var spArgument = result.FirstOrDefault(m => m.Argument.Equals(SmtpArgumentName.From)); Assert.IsNotNull(spArgument, "Did not return a From argument"); Assert.AreEqual("*****@*****.**", spArgument.Value); }
public void Parse_EHLOWithDomain_ReturnsResult() { // Arrange var testCommand = "EHLO SP test.com"; // Act var result = SmtpCommand.Parse(testCommand); // Assert Assert.IsTrue(result.Success); Assert.AreEqual(SmtpVerb.ExtendedHello, result.Result.Verb); var spArgument = result.Result.Arguments.FirstOrDefault(m => m.Argument.Equals(SmtpArgumentName.Sp)); Assert.IsNotNull(spArgument); Assert.AreEqual("test.com", spArgument.Value); }
public void Process(IConnection connection, SmtpCommand command) { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.ServiceReady, "Ready to start TLS")); connection.ApplyStreamFilter(stream => { SslStream sslStream = new SslStream(stream); sslStream.AuthenticateAsServer( connection.Server.Behaviour.GetSSLCertificate( connection), false, SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls, false); return sslStream; }); connection.Session.SecureConnection = true; }
/// <summary> /// Dispatches a command to the registered sub command matching the next verb in the command /// or writes an error to the client is no match was found. /// </summary> /// <param name="connection">The connection<see cref="Rnwood.SmtpServer.IConnection" />.</param> /// <param name="command">The command<see cref="Rnwood.SmtpServer.SmtpCommand" />.</param> /// <returns> /// A <see cref="System.Threading.Tasks.Task" /> representing the async operation. /// </returns> public virtual async Task Process(IConnection connection, SmtpCommand command) { SmtpCommand subrequest = new SmtpCommand(command.ArgumentsText); IVerb verbProcessor = this.SubVerbMap.GetVerbProcessor(subrequest.Verb); if (verbProcessor != null) { await verbProcessor.Process(connection, subrequest).ConfigureAwait(false); } else { await connection.WriteResponse( new SmtpResponse( StandardSmtpResponseCode.CommandParameterNotImplemented, "Subcommand {0} not implemented", subrequest.Verb)).ConfigureAwait(false); } }
public override void Process(IConnection connection, SmtpCommand command) { if (_eightBitMessage) { connection.SetReaderEncoding(Encoding.Default); } try { base.Process(connection, command); } finally { if (_eightBitMessage) { connection.SetReaderEncodingToDefault(); } } }
async ValueTask <SmtpCommand> ReadCommandAsync(ISessionContext context, CancellationToken cancellationToken) { var timeout = new CancellationTokenSource(context.ServerOptions.CommandWaitTimeout); var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancellationToken); try { SmtpCommand command = null; await context.Pipe.Input.ReadLineAsync( buffer => { var parser = new SmtpParser(_commandFactory); if (parser.TryMake(ref buffer, out command, out var errorResponse) == false) { throw new SmtpResponseException(errorResponse); } return(Task.CompletedTask); }, cancellationTokenSource.Token).ConfigureAwait(false); return(command); } catch (OperationCanceledException) { if (timeout.IsCancellationRequested) { throw new SmtpResponseException(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "Timeout whilst waiting for input."), true); } throw new SmtpResponseException(new SmtpResponse(SmtpReplyCode.ServiceClosingTransmissionChannel, "The session has be cancelled."), true); } finally { timeout.Dispose(); cancellationTokenSource.Dispose(); } }
/// <inheritdoc/> public async Task Process(IConnection connection, SmtpCommand command) { X509Certificate certificate = await connection.Server.Behaviour.GetSSLCertificate(connection).ConfigureAwait(false); if (certificate == null) { await connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.CommandNotImplemented, "TLS configuration error - no certificate")).ConfigureAwait(false); return; } await connection.WriteResponse(new SmtpResponse( StandardSmtpResponseCode.ServiceReady, "Ready to start TLS")).ConfigureAwait(false); SslProtocols sslProtos; string ver = Assembly.GetEntryAssembly()?.GetCustomAttribute <TargetFrameworkAttribute>()?.FrameworkName; if (ver == null || !ver.StartsWith(".NETCoreApp,")) { sslProtos = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Ssl3 | SslProtocols.Ssl2; } else { sslProtos = SslProtocols.None; } await connection.ApplyStreamFilter(async stream => { SslStream sslStream = new SslStream(stream); await sslStream.AuthenticateAsServerAsync( certificate, false, sslProtos, false).ConfigureAwait(false); return(sslStream); }).ConfigureAwait(false); connection.Session.SecureConnection = true; }
public bool IsCommandValid(SmtpCommand command) { switch (command) { case SmtpCommand.Help: case SmtpCommand.Helo: case SmtpCommand.Ehlo: case SmtpCommand.Rset: return true; case SmtpCommand.StartTls: return HasHelo && !HasMailFrom; case SmtpCommand.Mail: return HasHelo && !HasMailFrom; case SmtpCommand.Rcpt: return HasMailFrom; case SmtpCommand.Data: return HasRcptTo; case SmtpCommand.Quit: return true; } return false; }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { if (!string.IsNullOrEmpty(connection.Session.ClientName)) { await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.BadSequenceOfCommands, "You already said HELO")); return; } connection.Session.ClientName = command.ArgumentsText ?? ""; var text = new StringBuilder(); text.AppendLine("Nice to meet you."); foreach (var extnName in connection.ExtensionProcessors.SelectMany(extn => extn.EhloKeywords)) { text.AppendLine(extnName); } await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.Ok, text.ToString().TrimEnd())); }
public void Process(IConnection connection, SmtpCommand command) { X509Certificate certificate = connection.Server.Behaviour.GetSSLCertificate(connection); if (certificate == null) { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.CommandNotImplemented, "TLS configuration error - no certificate")); return; } connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.ServiceReady, "Ready to start TLS")); connection.ApplyStreamFilter(stream => { SslStream sslStream = new SslStream(stream); sslStream.AuthenticateAsServer(certificate , false, SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls, false); return(sslStream); }); connection.Session.SecureConnection = true; }
/// <inheritdoc/> public async Task Process(IConnection connection, SmtpCommand command) { await connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.OK, "Successfully did nothing")).ConfigureAwait(false); }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.OK, "Successfully did nothing")); }
public async Task ProcessAsync(IConnection connection, SmtpCommand command) { connection.AbortMessage(); await connection.WriteResponseAsync(new SmtpResponse(StandardSmtpResponseCode.OK, "Rset completed")); }
void QueueCommand(SmtpCommand type, string command) { if (queue == null) queue = new MemoryBlockStream (); var bytes = Encoding.UTF8.GetBytes (command + "\r\n"); queue.Write (bytes, 0, bytes.Length); queued.Add (type); }
void QueueCommand(SmtpCommand type, string command) { #if DEBUG Console.WriteLine ("C: {0}", command); #endif if (queue == null) queue = new MemoryBlockStream (); var bytes = Encoding.UTF8.GetBytes (command + "\r\n"); queue.Write (bytes, 0, bytes.Length); queued.Add (type); }
public void Process(IConnection connection, SmtpCommand command) { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.OK, "Sucessfully did nothing")); }
void QueueCommand (SmtpCommand type, string command, CancellationToken cancellationToken) { var bytes = Encoding.UTF8.GetBytes (command + "\r\n"); // Note: queued commands will be buffered by the stream Stream.Write (bytes, 0, bytes.Length, cancellationToken); queued.Add (type); }
public void Process(IConnection connection, SmtpCommand command) { connection.AbortMessage(); connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.OK, "Rset completed")); }
public void Process(IConnection connection, SmtpCommand command) { if (command.Arguments.Length > 0) { if (connection.Session.Authenticated) { throw new SmtpServerException(new SmtpResponse(StandardSmtpResponseCode.BadSequenceOfCommands, "Already authenticated")); } string mechanismId = command.Arguments[0]; IAuthMechanism mechanism = AuthExtensionProcessor.MechanismMap.Get(mechanismId); if (mechanism == null) { throw new SmtpServerException( new SmtpResponse(StandardSmtpResponseCode.CommandParameterNotImplemented, "Specified AUTH mechanism not supported")); } if (!AuthExtensionProcessor.IsMechanismEnabled(mechanism)) { throw new SmtpServerException( new SmtpResponse(StandardSmtpResponseCode.AuthenticationFailure, "Specified AUTH mechanism not allowed right now (might require secure connection etc)")); } IAuthMechanismProcessor authMechanismProcessor = mechanism.CreateAuthMechanismProcessor(connection); string initialData = null; if (command.Arguments.Length > 1) { initialData = string.Join(" ", command.Arguments.Skip(1).ToArray()); } AuthMechanismProcessorStatus status = authMechanismProcessor.ProcessResponse(initialData); while (status == AuthMechanismProcessorStatus.Continue) { string response = connection.ReadLine(); if (response == "*") { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.SyntaxErrorInCommandArguments, "Authentication aborted")); return; } status = authMechanismProcessor.ProcessResponse(response); } if (status == AuthMechanismProcessorStatus.Success) { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.AuthenticationOK, "Authenticated OK")); connection.Session.Authenticated = true; connection.Session.AuthenticationCredentials = authMechanismProcessor.Credentials; } else { connection.WriteResponse(new SmtpResponse(StandardSmtpResponseCode.AuthenticationFailure, "Authentication failure")); } } else { throw new SmtpServerException(new SmtpResponse(StandardSmtpResponseCode.SyntaxErrorInCommandArguments, "Must specify AUTH mechanism as a parameter")); } }