SMTP_Server.cs
上传用户:horngjaan
上传日期:2009-12-12
资源大小:2882k
文件大小:12k
源码类别:

Email服务器

开发平台:

C#

  1. using System;
  2. using System.IO;
  3. using System.ComponentModel;
  4. using System.Collections;
  5. using System.Diagnostics;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using System.Threading;
  9. using System.Windows.Forms;
  10. using LumiSoft.MailServer;
  11. namespace LumiSoft.MailServer.SMTP
  12. {
  13. #region Event delegates
  14. /// <summary>
  15. /// Represents the method that will handle the ValidateMailFrom event for POP3_Server.
  16. /// </summary>
  17. /// <param name="sender">The source of the event. </param>
  18. /// <param name="e">A ValidateSender_EventArgs that contains the event data.</param>
  19. public delegate void ValidateMailFromHandler(object sender,ValidateSender_EventArgs e);
  20. /// <summary>
  21. /// Represents the method that will handle the ValidateMailTo event for POP3_Server.
  22. /// </summary>
  23. /// <param name="sender">The source of the event. </param>
  24. /// <param name="e">A ValidateRecipient_EventArgs that contains the event data.</param>
  25. public delegate void ValidateMailToHandler(object sender,ValidateRecipient_EventArgs e);
  26. /// <summary>
  27. /// Represents the method that will handle the ValidateMailboxSize event for POP3_Server.
  28. /// </summary>
  29. /// <param name="sender">The source of the event. </param>
  30. /// <param name="e">A ValidateMailboxSize_EventArgs that contains the event data.</param>
  31. public delegate void ValidateMailboxSize(object sender,ValidateMailboxSize_EventArgs e);
  32. /// <summary>
  33. /// Represents the method that will handle the NewMailEvent event for POP3_Server.
  34. /// </summary>
  35. /// <param name="sender">The source of the event. </param>
  36. /// <param name="e">A NewMail_EventArgs that contains the event data.</param>
  37. public delegate void NewMailEventHandler(object sender,SMTP.NewMail_EventArgs e);
  38. #endregion
  39. /// <summary>
  40. /// SMTP server component.
  41. /// </summary>
  42. public class SMTP_Server : System.ComponentModel.Component
  43. {
  44. /// <summary>
  45. /// Required designer variable.
  46. /// </summary>
  47. private System.ComponentModel.Container components = null;
  48. private TcpListener SMTP_Listener  = null;
  49. private Hashtable   m_SessionTable = null;
  50. private string m_IPAddress          = "ALL";   // Holds IP Address, which to listen incoming calls.
  51. private int    m_port               = 25;      // Holds port number, which to listen incoming calls.
  52. private int    m_MaxThreads         = 20;      // Holds maximum allowed Worker Threads.
  53.         private bool   m_enabled            = false;   // If true listens incoming calls.
  54. private bool   m_LogCmds            = false;   // If true, writes POP3 commands to log file.
  55. private int    m_SessionIdleTimeOut = 80000;   // Holds session idle timeout.
  56. private int    m_CommandIdleTimeOut = 60000;   // Holds command ilde timeout.
  57. private int    m_MaxMessageSize     = 1000000; // Hold maximum message size.
  58. private int    m_MaxRecipients      = 100;     // Holds maximum recipient count.
  59. private int    m_MaxBadCommands     = 8;       // Holds maximum bad commands allowed to session.
  60.       
  61. #region Event declarations
  62. /// <summary>
  63. /// Occurs when new computer connected to POP3 server.
  64. /// </summary>
  65. public event ValidateIPHandler ValidateIPAddress = null;
  66. /// <summary>
  67. /// Occurs when connected user tryes to authenticate.
  68. /// </summary>
  69. public event AuthUserEventHandler AuthUser = null;
  70. /// <summary>
  71. /// Occurs when server needs to validate sender.
  72. /// </summary>
  73. public event ValidateMailFromHandler ValidateMailFrom = null;
  74. /// <summary>
  75. /// Occurs when server needs to validate recipient.
  76. /// </summary>
  77. public event ValidateMailToHandler ValidateMailTo = null;
  78. /// <summary>
  79. /// Occurs when server needs to validate recipient mailbox size.
  80. /// </summary>
  81. public event ValidateMailboxSize ValidateMailboxSize = null;
  82. /// <summary>
  83. /// Occurs when server has accepted message to store.
  84. /// </summary>
  85. public event NewMailEventHandler NewMailEvent = null;
  86. /// <summary>
  87. /// Occurs when server has system error(Unknown error).
  88. /// </summary>
  89. public event ErrorEventHandler SysError = null;
  90. /// <summary>
  91. /// Occurs when SMTP session has finished and session log is available.
  92. /// </summary>
  93. public event LogEventHandler SessionLog = null;
  94. #endregion
  95. #region Constructors
  96. /// <summary>
  97. /// 
  98. /// </summary>
  99. /// <param name="container"></param>
  100. public SMTP_Server(System.ComponentModel.IContainer container)
  101. {
  102. // Required for Windows.Forms Class Composition Designer support
  103. container.Add(this);
  104. InitializeComponent();
  105. //
  106. // TODO: Add any constructor code after InitializeComponent call
  107. //
  108. }
  109. /// <summary>
  110. /// 
  111. /// </summary>
  112. public SMTP_Server()
  113. {
  114. // Required for Windows.Forms Class Composition Designer support
  115. InitializeComponent();
  116. //
  117. // TODO: Add any constructor code after InitializeComponent call
  118. //
  119. }
  120. #endregion
  121. #region function Dispose
  122. /// <summary>
  123. /// Clean up any resources being used and STOPs SMTP server.
  124. /// </summary>
  125. public new void Dispose()
  126. {
  127. base.Dispose();
  128. Stop();
  129. }
  130. #endregion
  131.         
  132. #region Component Designer generated code
  133. /// <summary>
  134. /// Required method for Designer support - do not modify
  135. /// the contents of this method with the code editor.
  136. /// </summary>
  137. private void InitializeComponent()
  138. {
  139. components = new System.ComponentModel.Container();
  140. }
  141. #endregion
  142. #region function Start
  143. /// <summary>
  144. /// Starts SMTP Server.
  145. /// </summary>
  146. private void Start()
  147. {
  148. try
  149. {
  150. if(!m_enabled && !this.DesignMode){
  151. m_SessionTable = new Hashtable();
  152. Thread startSMTPServer = new Thread(new ThreadStart(Run));
  153. startSMTPServer.Start();
  154. }
  155. }
  156. catch(Exception x)
  157. {
  158. OnSysError(x,new System.Diagnostics.StackTrace());
  159. }
  160. }
  161. #endregion
  162. #region function Stop
  163. /// <summary>
  164. /// Stops SMTP Server.
  165. /// </summary>
  166. private void Stop()
  167. {
  168. try
  169. {
  170. if(SMTP_Listener != null){
  171. SMTP_Listener.Stop();
  172. }
  173. }
  174. catch(Exception x)
  175. {
  176. OnSysError(x,new System.Diagnostics.StackTrace());
  177. }
  178. }
  179. #endregion
  180. #region function Run
  181. /// <summary>
  182. /// Starts server message loop.
  183. /// </summary>
  184. private void Run()
  185. {
  186. try
  187. {
  188. // check which ip's to listen (all or assigned)
  189. if(m_IPAddress == "(All Unassigned)"){
  190. SMTP_Listener = new TcpListener(m_port);
  191. }
  192. else{
  193. SMTP_Listener = new TcpListener(IPAddress.Parse(m_IPAddress),m_port);
  194. }
  195. // Start listening
  196. SMTP_Listener.Start();
  197.                 
  198. //-------- Main Server message loop --------------------------------//
  199. while(true)
  200. {
  201. // Check if maximum allowed thread count isn't exceeded
  202. if(m_SessionTable.Count <= m_MaxThreads){
  203. // Thread is sleeping, until a client connects
  204. Socket clientSocket = SMTP_Listener.AcceptSocket();
  205. string sessionID = clientSocket.GetHashCode().ToString();
  206. //****
  207. _LogWriter logWriter        = new _LogWriter(this.SessionLog);
  208. SMTP_Session session        = new SMTP_Session(clientSocket,this,sessionID,logWriter);
  209. session.AuthUser            = this.AuthUser;
  210. session.NewMailEvent        = this.NewMailEvent;
  211. session.ValidateIPAddress   = this.ValidateIPAddress;
  212. session.ValidateMailFrom    = this.ValidateMailFrom;
  213. session.ValidateMailTo      = this.ValidateMailTo;
  214. session.ValidateMailboxSize = this.ValidateMailboxSize;
  215. ThreadStart tStart  = new ThreadStart(session.StartProcessing);
  216. Thread clientThread = new Thread(tStart);
  217. // Add session to session list
  218. AddSession(sessionID,session,logWriter);
  219. // Start proccessing
  220. clientThread.Start();
  221. }
  222. else{
  223. Thread.Sleep(300);
  224. }
  225. }
  226. }
  227. catch(ThreadInterruptedException e)
  228. {
  229. Thread.CurrentThread.Abort();
  230. }
  231. catch(Exception x)
  232. {
  233. if(x.Message != "A blocking operation was interrupted by a call to WSACancelBlockingCall"){
  234. OnSysError(x,new System.Diagnostics.StackTrace());
  235. }
  236. }
  237. }
  238. #endregion
  239. #region Session handling stuff
  240. #region function AddSession
  241. /// <summary>
  242. /// Adds session.
  243. /// </summary>
  244. /// <param name="sessionID">Session ID.</param>
  245. /// <param name="session">Session object.</param>
  246. /// <param name="logWriter">Log writer.</param>
  247. internal void AddSession(string sessionID,SMTP_Session session,_LogWriter logWriter)
  248. {
  249. m_SessionTable.Add(sessionID,session);
  250. if(m_LogCmds){
  251. logWriter.AddEntry("//----- Sys: 'Session:'" + sessionID + " added " + DateTime.Now);
  252. }
  253. }
  254. #endregion
  255. #region function RemoveSession
  256. /// <summary>
  257. /// Removes session.
  258. /// </summary>
  259. /// <param name="sessionID">Session ID.</param>
  260. /// <param name="logWriter">Log writer.</param>
  261. internal void RemoveSession(string sessionID,_LogWriter logWriter)
  262. {
  263. lock(m_SessionTable){
  264. if(!m_SessionTable.Contains(sessionID)){
  265. OnSysError(new Exception("Session '" + sessionID + "' doesn't exist."),new System.Diagnostics.StackTrace());
  266. return;
  267. }
  268. m_SessionTable.Remove(sessionID);
  269. }
  270. if(m_LogCmds){
  271. logWriter.AddEntry("//----- Sys: 'Session:'" + sessionID + " removed " + DateTime.Now);
  272. }
  273. }
  274. #endregion
  275. #endregion
  276. #region Properties Implementaion
  277. /// <summary>
  278. /// Gets or sets which IP address to listen.
  279. /// </summary>
  280. [
  281. Description("IP Address to Listen POP3 requests"),
  282. DefaultValue("ALL"),
  283. ]
  284. public string IpAddress 
  285. {
  286. get{ return m_IPAddress; }
  287. set{ m_IPAddress = value; }
  288. }
  289. /// <summary>
  290. /// Gets or sets which port to listen.
  291. /// </summary>
  292. [
  293. Description("Port to use for SMTP"),
  294. DefaultValue(25),
  295. ]
  296. public int Port 
  297. {
  298. get{ return m_port; }
  299. set{ m_port = value; }
  300. }
  301. /// <summary>
  302. /// Gets or sets maximum session threads.
  303. /// </summary>
  304. [
  305. Description("Maximum Allowed threads"),
  306. DefaultValue(20),
  307. ]
  308. public int Threads 
  309. {
  310. get{ return m_MaxThreads; }
  311. set{ m_MaxThreads = value; }
  312. }
  313. /// <summary>
  314. /// Runs and stops server.
  315. /// </summary>
  316. [
  317. Description("Use this property to run and stop SMTP Server"),
  318. DefaultValue(false),
  319. ]
  320. public bool Enabled 
  321. {
  322. get{ return m_enabled; }
  323. set{
  324. if(value){
  325. Start();
  326. }
  327. else{
  328. Stop();
  329. }
  330. m_enabled = value;
  331. }
  332. }
  333. /// <summary>
  334. /// Gets or sets if to log commands.
  335. /// </summary>
  336. public bool LogCommands
  337. {
  338. get{ return m_LogCmds; }
  339. set{ m_LogCmds = value; }
  340. }
  341. /// <summary>
  342. /// Session idle timeout.
  343. /// </summary>
  344. public int SessionIdleTimeOut 
  345. {
  346. get{ return m_SessionIdleTimeOut; }
  347. set{ m_SessionIdleTimeOut = value; }
  348. }
  349. /// <summary>
  350. /// Command idle timeout.
  351. /// </summary>
  352. public int CommandIdleTimeOut 
  353. {
  354. get{ return m_CommandIdleTimeOut; }
  355. set{ m_CommandIdleTimeOut = value; }
  356. }
  357. /// <summary>
  358. /// Maximum message size.
  359. /// </summary>
  360. public int MaxMessageSize 
  361. {
  362. get{ return m_MaxMessageSize; }
  363. set{ m_MaxMessageSize = value; }
  364. }
  365. /// <summary>
  366. /// Maximum recipients per message.
  367. /// </summary>
  368. public int MaxRecipients
  369. {
  370. get{ return m_MaxRecipients; }
  371. set{ m_MaxRecipients = value; }
  372. }
  373. /// <summary>
  374. /// Gets or sets maximum bad commands allowed to session.
  375. /// </summary>
  376. public int MaxBadCommands
  377. {
  378. get{ return m_MaxBadCommands; }
  379. set{ m_MaxBadCommands = value; }
  380. }
  381. #endregion
  382. #region Events Implementation
  383. /// <summary>
  384. /// Raises SysError event.
  385. /// </summary>
  386. /// <param name="x"></param>
  387. /// <param name="stackTrace"></param>
  388. internal void OnSysError(Exception x,StackTrace stackTrace)
  389. {
  390. if(this.SysError != null){
  391. this.SysError(this,new Error_EventArgs(x,stackTrace));
  392. }
  393. }
  394. #endregion
  395. }
  396. }