/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="clientSocket">Referance to socket.</param>
		/// <param name="server">Referance to FTP server.</param>
		/// <param name="sessionID">Session ID which is assigned to this session.</param>
		/// <param name="logWriter">Log writer.</param>
		public FTP_Session(Socket clientSocket,FTP_Server server,string sessionID,SocketLogger logWriter)
		{
			m_pSocket    = new BufferedSocket(clientSocket);
			m_pServer          = server;
			m_SessionID        = sessionID;
	//		m_pLogWriter       = logWriter;
			m_SessionStartTime = DateTime.Now;
			m_LastDataTime     = DateTime.Now;

			m_pSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.NoDelay,1);
			m_pSocket.Activity += new EventHandler(OnSocketActivity);

			// Start session proccessing
			StartSession();
		}
		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="clientSocket">Referance to socket.</param>
		/// <param name="server">Referance to IMAP server.</param>
		/// <param name="logWriter">Log writer.</param>
		internal IMAP_Session(Socket clientSocket,IMAP_Server server,SocketLogger logWriter)
		{
			m_pSocket = new BufferedSocket(clientSocket);
			m_pServer = server;

			m_SessionID        = Guid.NewGuid().ToString();			
			m_SessionStartTime = DateTime.Now;
			m_LastDataTime     = DateTime.Now;

			if(m_pServer.LogCommands){
				m_pSocket.Logger = logWriter;
				m_pSocket.Logger.SessionID = m_SessionID;
			}			

			m_pSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.NoDelay,1);
			m_pSocket.Activity += new EventHandler(OnSocketActivity);

			// Start session proccessing
			StartSession();
		}
		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="clientSocket">Referance to socket.</param>
		/// <param name="server">Referance to SMTP server.</param>
		/// <param name="logWriter">Log writer.</param>
		internal SMTP_Session(Socket clientSocket,SMTP_Server server,SocketLogger logWriter)
		{						
			m_pSocket    = new BufferedSocket(clientSocket);
			m_pServer    = server;
            
			m_pMsgStream   = new MemoryStream();
			m_SessionID    = Guid.NewGuid().ToString();
			m_BodyType     = BodyType.x7_bit;
			m_Forward_path = new Hashtable();
			m_CmdValidator = new SMTP_Cmd_Validator();
			m_SessionStart = DateTime.Now;
			m_LastDataTime = DateTime.Now;

			if(m_pServer.LogCommands){
				m_pSocket.Logger = logWriter;
				m_pSocket.Logger.SessionID = m_SessionID;
			}	

			m_pSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.NoDelay,1);
			m_pSocket.Activity += new EventHandler(OnSocketActivity);

			// Start session proccessing
			StartSession();
		}
		/// <summary>
		/// Connects to sepcified host.
		/// </summary>
		/// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
		/// <param name="host">Host name or IP address.</param>
		/// <param name="port">Port where to connect.</param>
		public void Connect(IPEndPoint localEndpoint,string host,int port)
		{	
			Socket s = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP);
			s.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReceiveTimeout,30000);
			s.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.NoDelay,1);
			
			m_pSocket = new BufferedSocket(s);
			if(localEndpoint != null){
				m_pSocket.Bind(localEndpoint);
			}
			m_pSocket.Activity += new EventHandler(m_pSocket_Activity);
	
			if(SessionLog != null){
				m_pLogger = new SocketLogger(s,SessionLog);
				m_pLogger.SessionID = Guid.NewGuid().ToString();
				m_pSocket.Logger = m_pLogger;
			}
		
			if(host.IndexOf("@") == -1){
				m_pSocket.Connect(new IPEndPoint(Dns_Client.Resolve(host)[0],port));					
			}
			else{
				//---- Parse e-domain -------------------------------//
				string domain = host;

				// eg. Ivx <*****@*****.**>
				if(domain.IndexOf("<") > -1 && domain.IndexOf(">") > -1){
					domain = domain.Substring(domain.IndexOf("<")+1,domain.IndexOf(">") - domain.IndexOf("<")-1);
				}

				if(domain.IndexOf("@") > -1){
					domain = domain.Substring(domain.LastIndexOf("@") + 1);
				}

				if(domain.Trim().Length == 0){
					if(m_pLogger != null){
						m_pLogger.AddTextEntry("Destination address '" + host + "' is invalid, aborting !");
					}
					throw new Exception("Destination address '" + host + "' is invalid, aborting !");
				}

				//--- Get MX record -------------------------------------------//
				Dns_Client dns = new Dns_Client();
				Dns_Client.DnsServers = m_pDnsServers;
				DnsServerResponse dnsResponse = dns.Query(domain,QTYPE.MX);

				switch(dnsResponse.ResponseCode)
				{
					case RCODE.NO_ERROR:
						MX_Record[] mxRecords = dnsResponse.GetMXRecords();

						// Try all available hosts by MX preference order, if can't connect specified host.
						foreach(MX_Record mx in mxRecords){
							try{
								if(m_pLogger != null){
									m_pLogger.AddTextEntry("Connecting with mx record to: " + mx.Host);
								}
								m_pSocket.Connect(new IPEndPoint(Dns_Client.Resolve(mx.Host)[0],port));
								break;
							}
							catch{ // Just skip and let for to try next host.									
								if(m_pLogger != null){
									m_pLogger.AddTextEntry("Failed connect to: " + mx.Host);
								}
							}
						}

						// None of MX didn't connect
						if(mxRecords.Length > 0 && !m_pSocket.Connected){
							throw new Exception("Destination email server is down");
						}

						/* Rfc 2821 5
						 If no MX records are found, but an A RR is found, the A RR is treated as
						 if it was associated with an implicit MX RR, with a preference of 0,
						 pointing to that host.
						*/
						if(mxRecords.Length == 0){
							// Try to connect with A record
							IPAddress[] ipEntry = null;
							try{
								if(m_pLogger != null){
									m_pLogger.AddTextEntry("No mx record, trying to get A record for: " + domain);
								}
								ipEntry = Dns_Client.Resolve(domain);								
							}
							catch{
								if(m_pLogger != null){
									m_pLogger.AddTextEntry("Invalid domain,no MX or A record: " + domain);
								}
								throw new Exception("Invalid domain,no MX or A record: " + domain);
							}

							try{
								if(m_pLogger != null){
									m_pLogger.AddTextEntry("Connecting with A record to:" + domain);
								}
								m_pSocket.Connect(new IPEndPoint(ipEntry[0],port));
							}
							catch{
								if(m_pLogger != null){
									m_pLogger.AddTextEntry("Failed connect to:" + domain);
								}
								throw new Exception("Destination email server is down");
							}
						}
						break;

					case RCODE.NAME_ERROR:
						if(m_pLogger != null){
							m_pLogger.AddTextEntry("Invalid domain,no MX or A record: " + domain);
						}
						throw new Exception("Invalid domain,no MX or A record: " + domain);

					case RCODE.SERVER_FAILURE:
						if(m_pLogger != null){
							m_pLogger.AddTextEntry("Dns server unvailable.");
						}
						throw new Exception("Dns server unvailable.");
					}					
			}
					
			/*
			 * Notes: Greeting may be single or multiline response.
			 *		
			 * Examples:
			 *		220<SP>SMTP server ready<CRLF> 
			 * 
			 *		220-SMTP server ready<CRLF>
			 *		220-Addtitional text<CRLF>
			 *		220<SP>final row<CRLF>
			 * 
			*/

			// Read server response
			string responseLine = m_pSocket.ReadLine(1000);
			while(!responseLine.StartsWith("220 ")){
				// If lisne won't start with 220, then its error response
				if(!responseLine.StartsWith("220")){
					throw new Exception(responseLine);
				}

				responseLine = m_pSocket.ReadLine(1000);
			}

			m_Connected = true;
		}
/*		/// <summary>
		/// Starts disconnecting SMTP client.
		/// </summary>
		public void BeginDisconnect()
		{
			if(!m_Connected){
				throw new Exception("You must connect first");
			}
		}*/

		#region method Disconnect

		/// <summary>
		/// Disconnects smtp client from server.
		/// </summary>
		public void Disconnect()
		{
            try{		
				if(m_pSocket != null && m_pSocket.Connected){
					m_pSocket.SendLine("QUIT");

					m_pSocket.Shutdown(SocketShutdown.Both);
				}
			}
			catch{	
			}

			m_pSocket = null;
			m_Connected = false;
			m_Supports_Size = false;
			m_Supports_Bdat = false;
			m_Supports_Login = false;
			m_Supports_CramMd5 = false;

			if(m_pLogger != null){
				m_pLogger.Flush();
				m_pLogger = null;
			}
		}
		/// <summary>
		/// Ends session, closes socket.
		/// </summary>
		private void EndSession()
		{
			try{
				// Write logs to log file, if needed
				if(m_pServer.LogCommands){
					m_pSocket.Logger.Flush();
				}

				if(m_pSocket != null){
					m_pSocket.Shutdown(SocketShutdown.Both);
					m_pSocket.Close();
					m_pSocket = null;
				}
			}
			catch{ // We don't need to check errors here, because they only may be Socket closing errors.
			}
			finally{
				m_pServer.RemoveSession(this);
			}
		}
        /// <summary>
        /// Closes connection to Pop33 server.
        /// </summary>
        public void Disconnect()
        {

            if (socketStream != null)
            {
                // Send QUIT
                socketStream.Write(Encoding.ASCII.GetBytes("QUIT"), 0, 4);
                socketStream.Close();
            }


            if (m_pLogger != null)
            {
                m_pLogger.Flush();
            }
            m_pLogger = null;

            m_pSocket = null;
            m_Connected = false;
            m_Authenticated = false;
        }
		/// <summary>
		/// Ends session, closes socket.
		/// </summary>
		private void EndSession()
		{			
			m_pServer.RemoveSession(this);

			// Write logs to log file, if needed
			if(m_pServer.LogCommands){
			//	m_pLogWriter.AddEntry("//----- Sys: 'Session:'" + this.SessionID + " removed " + DateTime.Now);
				
			//	m_pLogWriter.Flush();

				m_pSocket.Logger.Flush();
			}

			if(m_pSocket != null){
				m_pSocket.Shutdown(SocketShutdown.Both);
				m_pSocket.Close();
				m_pSocket = null;
			}
		}