SMTPContext.cs
上传用户:wdhx888
上传日期:2017-06-08
资源大小:112k
文件大小:6k
源码类别:

WEB邮件程序

开发平台:

C#

  1. namespace EricDaugherty.CSES.SmtpServer
  2. {
  3. using System;
  4. using System.Net.Sockets;
  5. using System.Text;
  6. using log4net;
  7. /// <summary>
  8. /// Maintains the current state for a SMTP client connection.
  9. /// </summary>
  10. /// <remarks>
  11. /// This class is similar to a HTTP Session.  It is used to maintain all
  12. /// the state information about the current connection.
  13. /// </remarks>
  14. public class SMTPContext : object
  15. {
  16. #region Constants
  17. private const string EOL = "rn";
  18. #endregion
  19. #region Variables
  20. /// <summary>The unique ID assigned to this connection</summary>
  21. private long connectionId;
  22. /// <summary>The socket to the client.</summary>
  23. private Socket socket;
  24. /// <summary>Last successful command received.</summary>
  25. private int lastCommand;
  26. /// <summary>The client domain, as specified by the helo command.</summary>
  27. private string clientDomain;
  28. /// <summary>The incoming message.</summary>
  29. private SMTPMessage message;
  30. /// <summary>Encoding to use to send/receive data from the socket.</summary>
  31. private Encoding encoding;
  32. /// <summary>
  33. /// It is possible that more than one line will be in
  34. /// the queue at any one time, so we need to store any input
  35. /// that has been read from the socket but not requested by the
  36. /// ReadLine command yet.
  37. /// </summary>
  38. private StringBuilder inputBuffer;
  39. /// <summary>Default Logger</summary>
  40. private static ILog log = LogManager.GetLogger( typeof( SMTPContext ) );
  41. /// <summary>Logs all IO.  Seperate from normal Logger.</summary>
  42. private static ILog ioLog = LogManager.GetLogger( "IO." + typeof( SMTPContext ) );
  43. #endregion
  44. #region Constructors
  45. /// <summary>
  46. /// Initialize this context for a given socket connection.
  47. /// </summary>
  48. public SMTPContext( long connectionId, Socket socket )
  49. {
  50. if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: New connection from client {1}", connectionId, socket.RemoteEndPoint ) );
  51. this.connectionId = connectionId;
  52. this.lastCommand = -1;
  53. this.socket = socket;
  54. message = new SMTPMessage();
  55. // Set the encoding to ASCII.  
  56. encoding = Encoding.ASCII;
  57. // Initialize the input buffer
  58. inputBuffer = new StringBuilder();
  59. }
  60. #endregion
  61. #region Properties
  62. /// <summary>
  63. /// The unique connection id.
  64. /// </summary>
  65. public long ConnectionId
  66. {
  67. get
  68. {
  69. return connectionId;
  70. }
  71. }
  72. /// <summary>
  73. /// Last successful command received.
  74. /// </summary>
  75. public int LastCommand
  76. {
  77. get
  78. {
  79. return lastCommand;
  80. }
  81. set
  82. {
  83. lastCommand = value;
  84. }
  85. }
  86. /// <summary>
  87. /// The client domain, as specified by the helo command.
  88. /// </summary>
  89. public string ClientDomain
  90. {
  91. get
  92. {
  93. return clientDomain;
  94. }
  95. set
  96. {
  97. clientDomain = value;
  98. }
  99. }
  100. /// <summary>
  101. /// The Socket that is connected to the client.
  102. /// </summary>
  103. public Socket Socket
  104. {
  105. get
  106. {
  107. return socket;
  108. }
  109. }
  110. /// <summary>
  111. /// The SMTPMessage that is currently being received.
  112. /// </summary>
  113. public SMTPMessage Message
  114. {
  115. get
  116. {
  117. return message;
  118. }
  119. set
  120. {
  121. message = value;
  122. }
  123. }
  124. #endregion
  125. #region Public Methods
  126. /// <summary>
  127. /// Writes the string to the socket as an entire line.  This
  128. /// method will append the end of line characters, so the data
  129. /// parameter should not contain them.
  130. /// </summary>
  131. /// <param name="data">The data to write the the client.</param>
  132. public void WriteLine( string data )
  133. {
  134. if( ioLog.IsDebugEnabled ) ioLog.Debug( String.Format( "Connection {0}: Wrote Line: {1}", connectionId, data ) );
  135. socket.Send( encoding.GetBytes( data + EOL ) );
  136. }
  137. /// <summary>
  138. /// Reads an entire line from the socket.  This method
  139. /// will block until an entire line has been read.
  140. /// </summary>
  141. public String ReadLine()
  142. {
  143. // If we already buffered another line, just return
  144. // from the buffer.
  145. string output = ReadBuffer();
  146. if( output != null )
  147. {
  148. return output;
  149. }
  150. // Otherwise, read more input.
  151. byte[] byteBuffer = new byte[80];
  152. int count;
  153. // Read from the socket until an entire line has been read.
  154. do
  155. {
  156. // Read the input data.
  157. count = socket.Receive( byteBuffer );
  158. if( count == 0 )
  159. {
  160. log.Debug( "Socket closed before end of line received." );
  161. return null;
  162. }
  163. inputBuffer.Append( encoding.GetString( byteBuffer, 0, count ) );
  164. if( ioLog.IsDebugEnabled ) ioLog.Debug( String.Format( "Connection {0}: Read: {1}", connectionId, inputBuffer ) );
  165. }
  166. while( (output = ReadBuffer()) == null );
  167. // IO Log statement is in ReadBuffer...
  168. return output;
  169. }
  170. /// <summary>
  171. /// Resets this context for a new message
  172. /// </summary>
  173. public void Reset()
  174. {
  175. if( log.IsDebugEnabled ) log.Debug( String.Format( "Connection {0}: Reset" , connectionId ) );
  176. message = new SMTPMessage();
  177. lastCommand = SMTPProcessor.COMMAND_HELO;
  178. }
  179. /// <summary>
  180. /// Closes the socket connection to the client and performs any cleanup.
  181. /// </summary>
  182. public void Close()
  183. {
  184. socket.Close();
  185. }
  186. #endregion
  187. #region Private Methods
  188. /// <summary>
  189. /// Helper method that returns the first full line in
  190. /// the input buffer, or null if there is no line in the buffer.
  191. /// If a line is found, it will also be removed from the buffer.
  192. /// </summary>
  193. private string ReadBuffer()
  194. {
  195. // If the buffer has data, check for a full line.
  196. if( inputBuffer.Length > 0 )
  197. {
  198. string buffer = inputBuffer.ToString();
  199. int eolIndex = buffer.IndexOf( EOL );
  200. if( eolIndex != -1 )
  201. {
  202. string output = buffer.Substring( 0, eolIndex );
  203. inputBuffer = new StringBuilder( buffer.Substring( eolIndex + 2 ) );
  204. if( ioLog.IsDebugEnabled ) ioLog.Debug( String.Format( "Connection {0}: Read Line: {1}", connectionId, output ) );
  205. return output;
  206. }
  207. }
  208. return null;
  209. }
  210. #endregion
  211. }
  212. }