SMTPContext.cs
上传用户:wdhx888
上传日期:2017-06-08
资源大小:112k
文件大小:6k
- namespace EricDaugherty.CSES.SmtpServer
- {
- using System;
- using System.Net.Sockets;
- using System.Text;
- using log4net;
-
- /// <summary>
- /// Maintains the current state for a SMTP client connection.
- /// </summary>
- /// <remarks>
- /// This class is similar to a HTTP Session. It is used to maintain all
- /// the state information about the current connection.
- /// </remarks>
- public class SMTPContext : object
- {
- #region Constants
-
- private const string EOL = "rn";
-
- #endregion
-
- #region Variables
-
- /// <summary>The unique ID assigned to this connection</summary>
- private long connectionId;
-
- /// <summary>The socket to the client.</summary>
- private Socket socket;
-
- /// <summary>Last successful command received.</summary>
- private int lastCommand;
-
- /// <summary>The client domain, as specified by the helo command.</summary>
- private string clientDomain;
-
- /// <summary>The incoming message.</summary>
- private SMTPMessage message;
-
- /// <summary>Encoding to use to send/receive data from the socket.</summary>
- private Encoding encoding;
-
- /// <summary>
- /// It is possible that more than one line will be in
- /// the queue at any one time, so we need to store any input
- /// that has been read from the socket but not requested by the
- /// ReadLine command yet.
- /// </summary>
- private StringBuilder inputBuffer;
-
- /// <summary>Default Logger</summary>
- private static ILog log = LogManager.GetLogger( typeof( SMTPContext ) );
-
- /// <summary>Logs all IO. Seperate from normal Logger.</summary>
- private static ILog ioLog = LogManager.GetLogger( "IO." + typeof( SMTPContext ) );
-
- #endregion
-
- #region Constructors
-
- /// <summary>
- /// Initialize this context for a given socket connection.
- /// </summary>
- public SMTPContext( long connectionId, Socket socket )
- {
- if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: New connection from client {1}", connectionId, socket.RemoteEndPoint ) );
-
- this.connectionId = connectionId;
- this.lastCommand = -1;
- this.socket = socket;
- message = new SMTPMessage();
-
- // Set the encoding to ASCII.
- encoding = Encoding.ASCII;
-
- // Initialize the input buffer
- inputBuffer = new StringBuilder();
- }
-
- #endregion
-
- #region Properties
-
- /// <summary>
- /// The unique connection id.
- /// </summary>
- public long ConnectionId
- {
- get
- {
- return connectionId;
- }
- }
-
- /// <summary>
- /// Last successful command received.
- /// </summary>
- public int LastCommand
- {
- get
- {
- return lastCommand;
- }
- set
- {
- lastCommand = value;
- }
- }
-
- /// <summary>
- /// The client domain, as specified by the helo command.
- /// </summary>
- public string ClientDomain
- {
- get
- {
- return clientDomain;
- }
- set
- {
- clientDomain = value;
- }
- }
-
- /// <summary>
- /// The Socket that is connected to the client.
- /// </summary>
- public Socket Socket
- {
- get
- {
- return socket;
- }
- }
-
- /// <summary>
- /// The SMTPMessage that is currently being received.
- /// </summary>
- public SMTPMessage Message
- {
- get
- {
- return message;
- }
- set
- {
- message = value;
- }
- }
-
- #endregion
-
- #region Public Methods
-
- /// <summary>
- /// Writes the string to the socket as an entire line. This
- /// method will append the end of line characters, so the data
- /// parameter should not contain them.
- /// </summary>
- /// <param name="data">The data to write the the client.</param>
- public void WriteLine( string data )
- {
- if( ioLog.IsDebugEnabled ) ioLog.Debug( String.Format( "Connection {0}: Wrote Line: {1}", connectionId, data ) );
- socket.Send( encoding.GetBytes( data + EOL ) );
- }
-
- /// <summary>
- /// Reads an entire line from the socket. This method
- /// will block until an entire line has been read.
- /// </summary>
- public String ReadLine()
- {
- // If we already buffered another line, just return
- // from the buffer.
- string output = ReadBuffer();
- if( output != null )
- {
- return output;
- }
-
- // Otherwise, read more input.
- byte[] byteBuffer = new byte[80];
- int count;
-
- // Read from the socket until an entire line has been read.
- do
- {
- // Read the input data.
- count = socket.Receive( byteBuffer );
-
- if( count == 0 )
- {
- log.Debug( "Socket closed before end of line received." );
- return null;
- }
- inputBuffer.Append( encoding.GetString( byteBuffer, 0, count ) );
- if( ioLog.IsDebugEnabled ) ioLog.Debug( String.Format( "Connection {0}: Read: {1}", connectionId, inputBuffer ) );
- }
- while( (output = ReadBuffer()) == null );
-
- // IO Log statement is in ReadBuffer...
-
- return output;
- }
-
- /// <summary>
- /// Resets this context for a new message
- /// </summary>
- public void Reset()
- {
- if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: Reset" , connectionId ) );
- message = new SMTPMessage();
- lastCommand = SMTPProcessor.COMMAND_HELO;
- }
-
- /// <summary>
- /// Closes the socket connection to the client and performs any cleanup.
- /// </summary>
- public void Close()
- {
- socket.Close();
- }
-
- #endregion
-
- #region Private Methods
-
- /// <summary>
- /// Helper method that returns the first full line in
- /// the input buffer, or null if there is no line in the buffer.
- /// If a line is found, it will also be removed from the buffer.
- /// </summary>
- private string ReadBuffer()
- {
- // If the buffer has data, check for a full line.
- if( inputBuffer.Length > 0 )
- {
- string buffer = inputBuffer.ToString();
- int eolIndex = buffer.IndexOf( EOL );
- if( eolIndex != -1 )
- {
- string output = buffer.Substring( 0, eolIndex );
- inputBuffer = new StringBuilder( buffer.Substring( eolIndex + 2 ) );
- if( ioLog.IsDebugEnabled ) ioLog.Debug( String.Format( "Connection {0}: Read Line: {1}", connectionId, output ) );
- return output;
- }
- }
- return null;
- }
-
- #endregion
- }
- }