/// <summary> /// Handle the RCPT TO:<address> command. /// </summary> private void Rcpt( SMTPContext context, string argument ) { if( context.LastCommand == COMMAND_MAIL || context.LastCommand == COMMAND_RCPT ) { string address = ParseAddress( argument ); if( address != null ) { try { EmailAddress emailAddress = new EmailAddress( address ); // Check to make sure we want to accept this message. //if( recipientFilter.AcceptRecipient( context, emailAddress ) ) //{ context.Message.AddToAddress( emailAddress ); context.LastCommand = COMMAND_RCPT; context.WriteLine( MESSAGE_OK ); //if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: RcptTo address: {1} accepted.", context.ConnectionId, address ) ); //} //else //{ // context.WriteLine(MESSAGE_UNKNOWN_USER); //if (log.IsDebugEnabled) log.Debug(String.Format("Connection {0}: RcptTo address: {1} rejected. Did not pass Address Filter.", context.ConnectionId, address)); //} } catch( InvalidEmailAddressException ) { //if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: RcptTo argument: {1} rejected. Should be from:<*****@*****.**>", context.ConnectionId, argument ) ); context.WriteLine( MESSAGE_INVALID_ADDRESS ); } } else { //if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: RcptTo argument: {1} rejected. Should be from:<*****@*****.**>", context.ConnectionId, argument ) ); context.WriteLine( MESSAGE_INVALID_ADDRESS ); } } else { context.WriteLine( MESSAGE_INVALID_COMMAND_ORDER ); } }
private void Data( SMTPContext context ) { context.WriteLine( MESSAGE_START_DATA ); SMTPMessage message = context.Message; IPEndPoint clientEndPoint = (IPEndPoint) context.Socket.RemoteEndPoint; StringBuilder header = new StringBuilder(); header.Append( String.Format( "Received: from {0} ({0} [{1}])", context.ClientDomain, clientEndPoint.Address ) ); header.Append( "\r\n" ); header.Append( String.Format( " by {0} (Sitefinity's Mail Server)", domain ) ); header.Append( "\r\n" ); header.Append( " " + System.DateTime.Now ); header.Append( "\r\n" ); message.AddData( header.ToString() ); String line = context.ReadLine(); while( !line.Equals( "." ) ) { message.AddData( line ); message.AddData( "\r\n" ); line = context.ReadLine(); } // Spool the message messageSpool.SpoolMessage( message ); context.WriteLine( MESSAGE_OK ); OnMessageReceived(new MessageEventArgs(message)); // Reset the connection. context.Reset(); }
/// <summary> /// Reset the connection state. /// </summary> private void Rset( SMTPContext context ) { if( context.LastCommand != -1 ) { // Dump the message and reset the context. context.Reset(); context.WriteLine( MESSAGE_OK ); } else { context.WriteLine( MESSAGE_INVALID_COMMAND_ORDER ); } }
/// <summary> /// Handle the MAIL FROM:<address> command. /// </summary> private void Mail( SMTPContext context, string argument ) { bool addressValid = false; if( context.LastCommand == COMMAND_HELO ) { string address = ParseAddress( argument ); if( address != null ) { try { EmailAddress emailAddress = new EmailAddress( address ); context.Message.FromAddress = emailAddress; context.LastCommand = COMMAND_MAIL; addressValid = true; context.WriteLine( MESSAGE_OK ); //if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: MailFrom address: {1} accepted.", context.ConnectionId, address ) ); } catch( InvalidEmailAddressException ) { // This is fine, just fall through. } } // If the address is invalid, inform the client. if( !addressValid ) { //if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: MailFrom argument: {1} rejected. Should be from:<*****@*****.**>", context.ConnectionId, argument ) ); context.WriteLine( MESSAGE_INVALID_ADDRESS ); } } else { context.WriteLine( MESSAGE_INVALID_COMMAND_ORDER ); } }
/// <summary> /// Handles the HELO command. /// </summary> private void Helo( SMTPContext context, String[] inputs ) { if( context.LastCommand == -1 ) { if( inputs.Length == 2 ) { context.ClientDomain = inputs[1]; context.LastCommand = COMMAND_HELO; context.WriteLine( HeloResponse ); } else { context.WriteLine( MESSAGE_INVALID_ARGUMENT_COUNT ); } } else { context.WriteLine( MESSAGE_INVALID_COMMAND_ORDER ); } }
/// <summary> /// Handles the command input from the client. This /// message returns when the client issues the quit command. /// </summary> private void ProcessCommands( SMTPContext context ) { bool isRunning = true; String inputLine; // Loop until the client quits. while( isRunning ) { try { inputLine = context.ReadLine(); if( inputLine == null ) { isRunning = false; context.Close(); continue; } //log.Debug( "ProcessCommands Read: " + inputLine ); String[] inputs = inputLine.Split( " ".ToCharArray() ); switch( inputs[0].ToLower() ) { case "helo": case "ehlo": Helo( context, inputs ); break; case "rset": Rset( context ); break; case "noop": context.WriteLine( MESSAGE_OK ); break; case "quit": isRunning = false; context.WriteLine( MESSAGE_GOODBYE ); context.Close(); break; case "mail": if( inputs[1].ToLower().StartsWith( "from" ) ) { Mail( context, inputLine.Substring( inputLine.IndexOf( " " ) ) ); break; } context.WriteLine( MESSAGE_UNKNOWN_COMMAND ); break; case "rcpt": if( inputs[1].ToLower().StartsWith( "to" ) ) { Rcpt( context, inputLine.Substring( inputLine.IndexOf( " " ) ) ); break; } context.WriteLine( MESSAGE_UNKNOWN_COMMAND ); break; case "data": Data( context ); break; default: context.WriteLine( MESSAGE_UNKNOWN_COMMAND ); break; } } catch( Exception exception ) { //log.Error( String.Format( "Connection {0}: Exception occured while processing commands: {1}", context.ConnectionId, exception ), exception ); context.WriteLine( MESSAGE_SYSTEM_ERROR ); } } }
/// <summary> /// Sends the welcome greeting to the client. /// </summary> private void SendWelcomeMessage( SMTPContext context ) { context.WriteLine( WelcomeMessage ); }
/// <summary> /// ProcessConnection handles a connected TCP Client /// and performs all necessary interaction with this /// client to comply with RFC821. This method is thread /// safe. /// </summary> public void ProcessConnection( Socket socket ) { long currentConnectionId = 0; // Really only need to lock on the long, but that is not // allowed. Is there a better way to do this? lock( this ) { currentConnectionId = connectionId++; } SMTPContext context = new SMTPContext( currentConnectionId, socket ); try { SendWelcomeMessage( context ); ProcessCommands( context ); } catch( Exception exception ) { //log.Error( String.Format( "Connection {0}: Error: {1}", context.ConnectionId, exception ), exception ); } }
/// <summary> /// Accepts only local email. /// </summary> /// <param name='context'>The SMTPContext</param> /// <param name='recipient'>TODO - add parameter description</param> public virtual bool AcceptRecipient( SMTPContext context, EmailAddress recipient ) { return domain.Equals( recipient.Domain ); }