Click here to Skip to main content
15,896,557 members
Articles / Programming Languages / C#

LumiSoft MailServer

Rate me:
Please Sign up or sign in to vote.
3.79/5 (22 votes)
17 Nov 2006CPOL1 min read 323.4K   4.9K   74  
Full featured SMTP/POP3/IMAP server
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Net;

using LumiSoft.Net;
using LumiSoft.Net.SMTP.Client;
using LumiSoft.Net.Mime;

namespace LumiSoft.MailServer.Relay
{
    /// <summary>
    /// This class implements relay server session.
    /// </summary>
    public class Relay_Session
    {
        private Relay_Server     m_pRelayServer    = null;
        private string           m_MessageFile     = "";
		private bool             m_relay_retry     = false;
        private FileStream       m_pMessageStream  = null;
		private RelayInfo        m_pRelayInfo      = null;
        private string           m_SessionID       = "";
        private DateTime         m_SessionStartTime;
        private SmtpClientEx     m_pSmtpClient     = null;
        private Queue<IPAddress> m_pConnectPoints  = null;
        private IPEndPoint       m_pRemoteEndPoint = null;
        private bool             m_Ended           = false;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="server">Reference to owner relay server.</param>
        /// <param name="file">Message file to relay.</param>
		/// <param name="relay_retry">If true then first time relay, otherwise retry attempt.</param>
        public Relay_Session(Relay_Server server,string file,bool relay_retry)
        {
            m_pRelayServer = server;
            m_MessageFile  = file;
            m_relay_retry  = relay_retry;

            m_pMessageStream = File.Open(m_MessageFile,FileMode.Open,FileAccess.ReadWrite,FileShare.Read);
			m_pRelayInfo = new RelayInfo(m_pMessageStream,m_pRelayServer.UndeliveredAfter,m_pRelayServer.UndeliveredWarningAfter);
            m_SessionID = Guid.NewGuid().ToString();
            m_SessionStartTime = DateTime.Now;
            m_pSmtpClient = new SmtpClientEx();
			m_pSmtpClient.DnsServers = new string[]{m_pRelayServer.Dns1,m_pRelayServer.Dns2};
			if(m_pRelayServer.LogCommands){
                m_pSmtpClient.SessionLog += new LogEventHandler(OnSMTP_LogPart);
			}

            m_pConnectPoints = new Queue<IPAddress>();
        }
        
        #region method Dispose

        /// <summary>
        /// Clean up any resources beeing used.
        /// </summary>
        public void Dispose()
        {               
            if(m_pMessageStream != null){
                try{
                    m_pMessageStream.Dispose();
                }
                catch{
                }
                m_pMessageStream = null;
            }
            if(m_pSmtpClient != null){
                try{
                    m_pSmtpClient.Dispose();
                    m_pSmtpClient = null;
                }
                catch{
                }
            }
            m_pRemoteEndPoint = null;
        }

        #endregion


        #region method Start

        /// <summary>
        /// Starts relay session processing.
        /// </summary>
        public void Start()
        {
            try{               
				// Forward host is specified, use it
				if(m_pRelayInfo.ForwardHost.Length > 0){
                    string[] host_port = m_pRelayInfo.ForwardHost.Split(':');
                    int port = 25;
                    // SMTP port specified
                    if(host_port.Length == 2){
                        port = Convert.ToInt32(host_port[1]);
                    }

                    m_pSmtpClient.BeginConnect(new IPEndPoint(m_pRelayServer.SendingIP,0),host_port[0],port,false,new CommadCompleted(this.ConnectCompleted));		
				}
				// Smart host enabled, use it
				else if(m_pRelayServer.UseSmartHost){
					m_pSmtpClient.BeginConnect(new IPEndPoint(m_pRelayServer.SendingIP,0),m_pRelayServer.SmartHost,m_pRelayServer.SmartHostPort,m_pRelayServer.SmartHostUseSSL,new CommadCompleted(this.ConnectCompleted));
				}
				// Use direct delivery
				else{
                    // Get all posssible destination IPs (MX records,A).
                    foreach(IPAddress ip in m_pSmtpClient.GetDestinations(m_pRelayInfo.To)){
                        m_pConnectPoints.Enqueue(ip);
                    }

                    // We din't get any connect point, ... that never should happen.
                    if(m_pConnectPoints.Count == 0){                        
                        End(false,new Exception("Failed to get any destination IP address, invalid email domain name '" + m_pRelayInfo.To + "' or destination dns down."));
                        return;
                    }
                 
                    // Get next available destination connection point.
                    m_pRemoteEndPoint = GetConnectionPoint();

                    // All connections to specified domain to all available IP addresses exceeded.
                    if(m_pRemoteEndPoint == null){
                        End(false,new Exception("All IP addresses maximum allowed connections are exceeded for email domain '" + m_pRelayInfo.To + "'."));
                        return;
                    }

					m_pSmtpClient.BeginConnect(new IPEndPoint(m_pRelayServer.SendingIP,0),m_pRemoteEndPoint.Address.ToString(),25,new CommadCompleted(this.ConnectCompleted));
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
			
				End(false,x);
			}
        }

        #endregion

        #region method End

		/// <summary>
		/// Ends RelaySession, does clean up.
		/// </summary>
		/// <param name="sendOk">Specifies if message sent ok.</param>
		/// <param name="exception">If sendOk=false, then exception is filled with error info.</param>
		private void End(bool sendOk,Exception exception)
		{	
			// This method may be called multiple times, if session timed out.  Just block it.
            lock(this){
			    if(m_Ended){
				    return;
			    }
			    m_Ended = true;
            }

			try{                        
                // If exception and logging enabled, log exception.
                try{
                    if(m_pSmtpClient.SessionActiveLog != null && exception != null){
                        m_pSmtpClient.SessionActiveLog.AddTextEntry("Exception: " + exception.Message);                    
                    }
                }
                catch{
                    // FIX ME: this returns error here if smtp client not connected and exception, because
                    // no logger created yet.
                }

				if(sendOk){
					Dispose();

					// Message sended successfuly, may delete it
					File.Delete(m_MessageFile);
				}
				else if(m_relay_retry){
					Dispose();

					// Move message to Retry folder.
					string msgFileName = Path.GetFileName(m_MessageFile);                    
                    string retryFolder = API_Utlis.EnsureFolder(m_pRelayServer.VirtualServer.MailStorePath + "Retry");
					File.Move(m_MessageFile,API_Utlis.PathFix(retryFolder + "\\" + msgFileName));
				}
				else if(!m_relay_retry){
					string error     = exception.Message;
					bool   permError = error.StartsWith("5"); // SMTP permanent errors 5xx
			
					// If destination recipient is invalid or Undelivered Date Exceeded, try to return message to sender
					if(permError || m_pRelayInfo.IsUndeliveredDateExceeded){							
						MakeUndeliveredNotify(m_pRelayInfo,error,m_pMessageStream);

						Dispose();

						// Undelivery note made, may delete message
						if(m_pRelayInfo.From.Length > 0){
							File.Delete(m_MessageFile);
						}
						// There isn't return address, can't send undelivery note
						else if(m_pRelayServer.StoreUndeliveredMessages){
							// Check if Directory exists, if not Create
							if(!Directory.Exists(m_pRelayServer.VirtualServer.MailStorePath + "Undelivered\\")){
								Directory.CreateDirectory(m_pRelayServer.VirtualServer.MailStorePath + "Undelivered\\");
							}
							File.Move(m_MessageFile,m_MessageFile.Replace("Retry","Undelivered"));
						}
					}
					else if(m_pRelayInfo.MustSendWarning){
						MakeUndeliveredWarning(m_pRelayInfo,error,m_pMessageStream);

						byte[] mustSendWarningBit = System.Text.Encoding.ASCII.GetBytes("1");
						m_pMessageStream.Position = m_pRelayInfo.WarningBitPos;
						m_pMessageStream.Write(mustSendWarningBit,0,mustSendWarningBit.Length);	
						
						Dispose();
					}
				
					Dispose();
				}
			}
			catch(Exception x){	
				Error.DumpError(x,new System.Diagnostics.StackTrace());
			}
			finally{
				m_pRelayServer.RemoveSession(this);                
                m_pRelayServer = null;
			}
		}

		#endregion

        #region method Kill

        /// <summary>
        /// Kills this session.
        /// </summary>
        /// <param name="text">Text to reply to connected server.</param>
        public void Kill(string text)
        {
            if(m_pSmtpClient != null && m_pSmtpClient.SessionActiveLog != null){
                m_pSmtpClient.SessionActiveLog.AddTextEntry(text);
            }

			End(false,new Exception(text));
        }

        #endregion


        #region method OnSMTP_LogPart

        private void OnSMTP_LogPart(object sender,Log_EventArgs e)
        {            
            Logger.WriteLog(m_pRelayServer.LogsPath + "relay-" + DateTime.Today.ToString("yyyyMMdd") + ".log",e.Logger);
        }

        #endregion


        #region method ConnectCompleted

		/// <summary>
		/// Is called when Connect completed.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="exception"></param>
		private void ConnectCompleted(LumiSoft.Net.SocketCallBackResult result,Exception exception)
		{
			try{
				if(LumiSoft.Net.SocketCallBackResult.Ok == result){
                    m_pRemoteEndPoint = (IPEndPoint)m_pSmtpClient.RemoteEndPoint;

					m_pSmtpClient.BeginEhlo(m_pRelayServer.HostName,new CommadCompleted(this.EhloCompleted));
				}
				else if(exception != null){
                    // Get next available destination connection point.
                    m_pRemoteEndPoint = GetConnectionPoint();

                    // We have next available connection point, try next.
                    if(m_pRemoteEndPoint != null){                        
                        m_pSmtpClient.BeginConnect(new IPEndPoint(m_pRelayServer.SendingIP,0),m_pRemoteEndPoint.Address.ToString(),25,new CommadCompleted(this.ConnectCompleted));
                    }
                    else{
					    End(false,exception);
                    }
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
				
				End(false,x);
			}
		}

		#endregion

		#region method EhloCompleted

		/// <summary>
		/// Is called when EHLO is completed.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="exception"></param>
		private void EhloCompleted(LumiSoft.Net.SocketCallBackResult result,Exception exception)
		{
			try{
				if(LumiSoft.Net.SocketCallBackResult.Ok == result){
					if(m_pRelayServer.UseSmartHost && m_pRelayServer.SmartHostUserName.Length > 0){
						m_pSmtpClient.BeginAuthenticate(m_pRelayServer.SmartHostUserName,m_pRelayServer.SmartHostPassword,new CommadCompleted(this.AuthenticationCompleted));
					}
					else{
						m_pSmtpClient.BeginSetSender(m_pRelayInfo.From,m_pMessageStream.Length - m_pMessageStream.Position,new CommadCompleted(this.SetSenderCompleted));
					}
				}
				else if(exception != null){
					End(false,exception);
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
				
				End(false,x);
			}
		}

		#endregion

		#region method AuthenticationCompleted

		/// <summary>
		/// Is called when authentication is completed.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="exception"></param>
		private void AuthenticationCompleted(LumiSoft.Net.SocketCallBackResult result,Exception exception)
		{
			try{
				if(LumiSoft.Net.SocketCallBackResult.Ok == result){
					m_pSmtpClient.BeginSetSender(m_pRelayInfo.From,-1,new CommadCompleted(this.SetSenderCompleted));
				}
				else if(exception != null){
					End(false,exception);
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
				
				End(false,exception);
			}
		}

		#endregion

		#region method SetSenderCompleted

		/// <summary>
		/// Is called SetSender completed.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="exception"></param>
		private void SetSenderCompleted(LumiSoft.Net.SocketCallBackResult result,Exception exception)
		{
			try{
				if(LumiSoft.Net.SocketCallBackResult.Ok == result){
					m_pSmtpClient.BeginAddRecipient(m_pRelayInfo.To,new CommadCompleted(this.SetRecipientCompleted));
				}
				else if(exception != null){
					End(false,exception);
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
				
				End(false,x);
			}
		}

		#endregion

		#region method SetRecipientCompleted

		/// <summary>
		/// Is called when SetRecipient completed.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="exception"></param>
		private void SetRecipientCompleted(LumiSoft.Net.SocketCallBackResult result,Exception exception)
		{
			try{
				if(LumiSoft.Net.SocketCallBackResult.Ok == result){
					m_pSmtpClient.BeginSendMessage(m_pMessageStream,new CommadCompleted(this.MessageSendingCompleted));                                    
				}
				else if(exception != null){
					End(false,exception);
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
				
				End(false,x);
			}
		}

		#endregion

		#region method MessageSendingCompleted

		/// <summary>
		/// Is called when MessageSending completed.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="exception"></param>
		private void MessageSendingCompleted(LumiSoft.Net.SocketCallBackResult result,Exception exception)
		{
			try{
				if(LumiSoft.Net.SocketCallBackResult.Ok == result){
					End(true,null);
				}
				else if(exception != null){
					End(false,exception);
				}
			}
			catch(Exception x){				
				End(false,x);
			}
		}

		#endregion

        
		#region method MakeUndeliveredNotify

		/// <summary>
		/// Creates undelivered notify for user and places it to relay folder.
		/// </summary>
		/// <param name="relayInfo">Relay info</param>
		/// <param name="error">SMTP returned error text.</param>
		/// <param name="file">Messsage file.</param>
		private void MakeUndeliveredNotify(RelayInfo relayInfo,string error,Stream file)
		{
			try{
				// If sender isn't specified, we can't send undelivery notify to sender.
				// Just skip undelivery notify sending.
				if(relayInfo.From.Length == 0){
					return;
				}

				file.Position = relayInfo.MessageStartPos;
                RelayVariablesManager variablesMgr = new RelayVariablesManager(this,error,file);
                file.Position = relayInfo.MessageStartPos;

                ServerReturnMessage messageTemplate = m_pRelayServer.UndeliveredMessage;
                if(messageTemplate == null){
                    string bodyRtf = "" +
                    "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Verdana;}{\\f1\\fswiss\\fprq2\\fcharset186 Verdana;}{\\f2\\fnil\\fcharset0 Verdana;}{\\f3\\fnil\\fcharset186 Verdana;}{\\f4\\fswiss\\fcharset0 Arial;}{\\f5\\fswiss\\fcharset186{\\*\\fname Arial;}Arial Baltic;}}\r\n" +
                    "{\\colortbl ;\\red0\\green64\\blue128;\\red255\\green0\\blue0;\\red0\\green128\\blue0;}\r\n" +
                    "\\viewkind4\\uc1\\pard\\f0\\fs20 Your message t\\lang1061\\f1 o \\cf1\\lang1033\\f2 <#relay.to>\\cf0\\f0 , dated \\b\\fs16 <#message.header[\"Date:\"]>\\b0\\fs20 , could not be delivered.\\par\r\n" +
                    "\\par\r\n" +
                    "Recipient \\i <#relay.to>'\\i0 s Server (\\cf1 <#relay.session_hostname>\\cf0 ) returned the following response: \\cf2 <#relay.error>\\cf0\\par\r\n" +
                    "\\par\r\n" +
                    "\\par\r\n" +
                    "\\b * Server will not attempt to deliver this message anymore\\b0 .\\par\r\n" +
                    "\\par\r\n" +
                    "--------\\par\r\n" +
                    "\\par\r\n" +
                    "Your original message is attached to this e-mail (\\b data.eml\\b0 )\\par\r\n" +
                    "\\par\r\n" +
                    "\\fs16 The tracking number for this message is \\cf3 <#relay.session_messageid>\\cf0\\fs20\\par\r\n" +
                    "\\lang1061\\f5\\par\r\n" +
                    "\\lang1033\\f2\\par\r\n" +
                    "}\r\n";

                    messageTemplate = new ServerReturnMessage("Undelivered notice: <#message.header[\"Subject:\"]>",bodyRtf);
                }

				// Make new message
				Mime m = new Mime();
				MimeEntity mainEntity = m.MainEntity;
				// Force to create From: header field
				mainEntity.From = new AddressList();
				mainEntity.From.Add(new MailboxAddress("postmaster"));
				// Force to create To: header field
				mainEntity.To = new AddressList();
				mainEntity.To.Add(new MailboxAddress(relayInfo.From));
				mainEntity.Subject = variablesMgr.Process(messageTemplate.Subject);
				mainEntity.ContentType = MediaType_enum.Multipart_mixed;

                string rtf = variablesMgr.Process(messageTemplate.BodyTextRtf);

                MimeEntity multipartAlternativeEntity = mainEntity.ChildEntities.Add();
                multipartAlternativeEntity.ContentType = MediaType_enum.Multipart_alternative;

				MimeEntity textEntity = multipartAlternativeEntity.ChildEntities.Add();
				textEntity.ContentType = MediaType_enum.Text_plain;
				textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
				textEntity.DataText = SCore.RtfToText(rtf);
                                
                MimeEntity htmlEntity = multipartAlternativeEntity.ChildEntities.Add();
				htmlEntity.ContentType = MediaType_enum.Text_html;
				htmlEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
				htmlEntity.DataText = SCore.RtfToHtml(rtf);

				MimeEntity attachmentEntity = mainEntity.ChildEntities.Add();
				attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;
				attachmentEntity.ContentDisposition = ContentDisposition_enum.Attachment;
				attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;
				attachmentEntity.ContentDisposition_FileName = "data.eml";
				attachmentEntity.DataFromStream(file);

				using(MemoryStream strm = new MemoryStream()){
					m.ToStream(strm);
					m_pRelayServer.VirtualServer.ProcessAndStoreMessage("",new string[]{relayInfo.From},strm,null);
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
			}
		}

		#endregion

		#region method MakeUndeliveredWarning

		/// <summary>
		/// Creates undelivered warning for user and places it to relay folder.
		/// </summary>
		/// <param name="relayInfo">Relay info</param>
		/// <param name="error">SMTP returned error text.</param>
		/// <param name="file">Messsage file.</param>
		private void MakeUndeliveredWarning(RelayInfo relayInfo,string error,Stream file)
		{	
			try{
				// If sender isn't specified, we can't send warning to sender.
				// Just skip warning sending.
				if(relayInfo.From.Length == 0){
					return;
				}

				file.Position = relayInfo.MessageStartPos;
                RelayVariablesManager variablesMgr = new RelayVariablesManager(this,error,file);
                file.Position = relayInfo.MessageStartPos;

                ServerReturnMessage messageTemplate = m_pRelayServer.UndeliveredMessage;
                if(messageTemplate == null){
                    string bodyRtf = "" +
                    "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Verdana;}{\\f1\\fnil\\fcharset186 Verdana;}{\\f2\\fswiss\\fcharset186{\\*\\fname Arial;}Arial Baltic;}{\\f3\\fnil\\fcharset0 Microsoft Sans Serif;}}\r\n" +
                    "{\\colortbl ;\\red0\\green64\\blue128;\\red255\\green0\\blue0;\\red0\\green128\\blue0;}\r\n" +
                    "\\viewkind4\\uc1\\pard\\f0\\fs20 This e-mail is generated by the Server(\\cf1 <#relay.hostname>\\cf0 )  to notify you, \\par\r\n" +
                    "\\lang1061\\f1 that \\lang1033\\f0 your message to \\cf1 <#relay.to>\\cf0  dated \\b\\fs16 <#message.header[\"Date:\"]>\\b0  \\fs20 could not be sent at the first attempt.\\par\r\n" +
                    "\\par\r\n" +
                    "Recipient \\i <#relay.to>'\\i0 s Server (\\cf1 <#relay.session_hostname>\\cf0 ) returned the following response: \\cf2 <#relay.error>\\cf0\\par\r\n" +
                    "\\par\r\n" +
                    "\\par\r\n" +
                    "Please note Server will attempt to deliver this message for \\b <#relay.undelivered_after>\\b0  hours.\\par\r\n" +
                    "\\par\r\n" +
                    "--------\\par\r\n" +
                    "\\par\r\n" +
                    "Your original message is attached to this e-mail (\\b data.eml\\b0 )\\par\r\n" +
                    "\\par\r\n" +
                    "\\fs16 The tracking number for this message is \\cf3 <#relay.session_messageid>\\cf0\\fs20\\par\r\n" +
                    "\\lang1061\\f2\\par\r\n" +
                    "\\pard\\lang1033\\f3\\fs17\\par\r\n" +
                    "}\r\n";

                    messageTemplate = new ServerReturnMessage("Delayed delivery notice: <#message.header[\"Subject:\"]>",bodyRtf);
                }
                              
				// Make new message
				Mime m = new Mime();
				MimeEntity mainEntity = m.MainEntity;
				// Force to create From: header field
				mainEntity.From = new AddressList();
				mainEntity.From.Add(new MailboxAddress("postmaster"));
				// Force to create To: header field
				mainEntity.To = new AddressList();
				mainEntity.To.Add(new MailboxAddress(relayInfo.From));
				mainEntity.Subject = variablesMgr.Process(messageTemplate.Subject);
				mainEntity.ContentType = MediaType_enum.Multipart_mixed;

                string rtf = variablesMgr.Process(messageTemplate.BodyTextRtf);

				MimeEntity multipartAlternativeEntity = mainEntity.ChildEntities.Add();
                multipartAlternativeEntity.ContentType = MediaType_enum.Multipart_alternative;

				MimeEntity textEntity = multipartAlternativeEntity.ChildEntities.Add();
				textEntity.ContentType = MediaType_enum.Text_plain;
				textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
				textEntity.DataText = SCore.RtfToText(rtf);
                                
                MimeEntity htmlEntity = multipartAlternativeEntity.ChildEntities.Add();
				htmlEntity.ContentType = MediaType_enum.Text_html;
				htmlEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
				htmlEntity.DataText = SCore.RtfToHtml(rtf);

				MimeEntity attachmentEntity = mainEntity.ChildEntities.Add();
				attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;
				attachmentEntity.ContentDisposition = ContentDisposition_enum.Attachment;
				attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;
				attachmentEntity.ContentDisposition_FileName = "data.eml";
				attachmentEntity.DataFromStream(file);

				using(MemoryStream strm = new MemoryStream()){
					m.ToStream(strm);
					m_pRelayServer.VirtualServer.ProcessAndStoreMessage("",new string[]{relayInfo.From},strm,null);
				}
			}
			catch(Exception x){
				Error.DumpError(x,new System.Diagnostics.StackTrace());
			}
		}

		#endregion

        #region method GetConnectionPoint

        /// <summary>
        /// Gets next connection point form available connection points queue. Returns null if none is available.
        /// Also connection points what maximum allowed connections exceeded, will be skiped.
        /// </summary>
        /// <returns>Returns connection point or null if none available.</returns>
        private IPEndPoint GetConnectionPoint()
        {
            // Try to get IP which maximum connections per IP isn't exceeded.
            while(m_pConnectPoints.Count > 0){
                IPAddress ip = m_pConnectPoints.Dequeue();
                // Check if specified IP maximum allowed connections exceeded.
                if(m_pRelayServer.MaximumConnectionsPerIP == 0 || m_pRelayServer.GetRelayConnections(ip) <= m_pRelayServer.MaximumConnectionsPerIP){
                    return new IPEndPoint(ip,0);
                }
                else if(m_pSmtpClient.SessionActiveLog != null){
                    m_pSmtpClient.SessionActiveLog.AddTextEntry("Skiping IP '" + ip.ToString() + "' maximum connections to that IP exceeded.");
                }
            }

            return null;
        }

        #endregion


        #region Properties Implementation

        /// <summary>
        /// Gets relay session ID.
        /// </summary>
        public string SessionID
        {
            get{ return m_SessionID; }
        }

        /// <summary>
        /// Gets session start time.
        /// </summary>
        public DateTime SessionStartTime
        {
            get{ return m_SessionStartTime; }
        }

        /// <summary>
		/// Gets session local endpoint.
		/// </summary>
		public EndPoint LocalEndPoint
		{
			get{ return m_pSmtpClient.LocalEndpoint; }
		}

		/// <summary>
		/// Gets session remote endpoint.
		/// </summary>
		public IPEndPoint RemoteEndPoint
		{
			get{ return (IPEndPoint)m_pRemoteEndPoint; }
		}

        /// <summary>
        /// Gets time when was session last activity.
        /// </summary>
        public DateTime LastActivity
        {
            get{ return m_pSmtpClient.LastDataTime; }
        }

        /// <summary>
        /// Gets how many seconds has left before timout is triggered.
        /// </summary>
        public int ExpectedTimeout
        {
            get{
                return (int)(m_pRelayServer.SessionIdleTimeout - ((DateTime.Now.Ticks - LastActivity.Ticks) / 10000));
            }
        }

        /// <summary>
        /// Gets log entries that are currently in log buffer.
        /// </summary>
        public SocketLogger SessionActiveLog
        {
            get{ return m_pSmtpClient.SessionActiveLog; }
        }

        /// <summary>
        /// Gets how many bytes are readed through this session.
        /// </summary>
        public long ReadedCount
        {
            get{ return m_pSmtpClient.ReadedCount; }
        }
        
        /// <summary>
        /// Gets how many bytes are written through this session.
        /// </summary>
        public long WrittenCount
        {
            get{ return m_pSmtpClient.WrittenCount; }
        }
        
        /// <summary>
        /// Gets if the connection is an SSL connection.
        /// </summary>
        public bool IsSecureConnection
        {
            get{ return m_pSmtpClient.IsSecureConnection; }
        }

        /// <summary>
        /// Gets file name which is relayed by this session.
        /// </summary>
        public string FileName
        {
            get{ return m_MessageFile; }
        }

        /// <summary>
        /// Gets relay destination recipient email address.
        /// </summary>
        public string To
        {
            get{ return m_pRelayInfo.To; }
        }

        /// <summary>
        /// Gets orginal sender email address who sent this relay message.
        /// </summary>
        public string From
        {
            get{ return m_pRelayInfo.From; }
        }

        /// <summary>
        /// Gets connected host name. If no connected host or name getting failed, returns "".
        /// </summary>
        public string ConnectedHostName
        {
            get{
                if(m_pRemoteEndPoint != null){
                    try{
                        return Dns.GetHostEntry(((IPEndPoint)m_pSmtpClient.RemoteEndPoint).Address).HostName;
                    }
                    catch{
                        return m_pRemoteEndPoint.Address.ToString();
                    }
                }
                
                return ""; 
            }
        }

        /// <summary>
        /// Gets relay message ID.
        /// </summary>
        public string MessageID
        {
            get{ return Path.GetFileNameWithoutExtension(m_MessageFile); }
        }


        /// <summary>
        /// Gets relay session owner relay server.
        /// </summary>
        internal Relay_Server OwnerServer
        {
            get{ return m_pRelayServer; }
        }

        #endregion

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Estonia Estonia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions