www.pudn.com > MailAccess.rar > POPClient.cs


using System; 
using System.Net.Sockets; 
using System.IO; 
using System.Threading; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Collections; 
 
namespace OpenPOP.POP3 
{ 
	public class POPClient 
	{ 
		public event EventHandler CommunicationBegan; 
		public event EventHandler CommunicationOccured; 
		public event EventHandler CommunicationLost; 
		public event EventHandler AuthenticationBegan; 
		public event EventHandler AuthenticationFinished; 
		public event EventHandler MessageTransferBegan; 
		public event EventHandler MessageTransferFinished; 
		internal void OnCommunicationBegan(EventArgs e) 
		{ 
			if (CommunicationBegan != null) 
				CommunicationBegan(this, e); 
		} 
 
		internal void OnCommunicationOccured(EventArgs e) 
		{ 
			if (CommunicationOccured != null) 
				CommunicationOccured(this, e); 
		} 
 
		internal void OnCommunicationLost(EventArgs e) 
		{ 
			if (CommunicationLost != null) 
				CommunicationLost(this, e); 
		} 
 
		internal void OnAuthenticationBegan(EventArgs e) 
		{ 
			if (AuthenticationBegan != null) 
				AuthenticationBegan(this, e); 
		} 
 
		internal void OnAuthenticationFinished(EventArgs e) 
		{ 
			if (AuthenticationFinished != null) 
				AuthenticationFinished(this, e); 
		} 
 
		internal void OnMessageTransferBegan(EventArgs e) 
		{ 
			if (MessageTransferBegan != null) 
				MessageTransferBegan(this, e); 
		} 
		 
		internal void OnMessageTransferFinished(EventArgs e) 
		{ 
			if (MessageTransferFinished != null) 
				MessageTransferFinished(this, e); 
		} 
 
		private const string RESPONSE_OK="+OK"; 
		//private const string RESPONSE_ERR="-ERR"; 
		private TcpClient clientSocket=null;		 
		private StreamReader reader; 
		private StreamWriter writer; 
		private string _Error = ""; 
		private int _receiveTimeOut=60000; 
		private int _sendTimeOut=60000; 
		private int _receiveBufferSize=4090; 
		private int _sendBufferSize=4090; 
		private string _basePath=null; 
		private bool _receiveFinish=false; 
		private bool _autoDecodeMSTNEF=true; 
		private int _waitForResponseInterval=200; 
		private int _receiveContentSleepInterval=100; 
		private string _aPOPTimestamp; 
		private string _lastCommandResponse; 
		private bool _connected=true; 
		public bool Connected 
		{ 
			get{return _connected;} 
		} 
 
		public string APOPTimestamp 
		{ 
			get{return _aPOPTimestamp;} 
		} 
		public int ReceiveContentSleepInterval 
		{ 
			get{return _receiveContentSleepInterval;} 
			set{_receiveContentSleepInterval=value;} 
		} 
		public int WaitForResponseInterval 
		{ 
			get{return _waitForResponseInterval;} 
			set{_waitForResponseInterval=value;} 
		} 
		public bool AutoDecodeMSTNEF 
		{ 
			get{return _autoDecodeMSTNEF;} 
			set{_autoDecodeMSTNEF=value;} 
		} 
		public string BasePath 
		{ 
			get{return _basePath;} 
			set 
			{ 
				try 
				{ 
					if(value.EndsWith("\\")) 
						_basePath=value; 
					else 
						_basePath=value+"\\"; 
				} 
				catch 
				{ 
				} 
			} 
		} 
		public int ReceiveTimeOut 
		{ 
			get{return _receiveTimeOut;} 
			set{_receiveTimeOut=value;} 
		} 
		public int SendTimeOut 
		{ 
			get{return _sendTimeOut;} 
			set{_sendTimeOut=value;} 
		} 
		public int ReceiveBufferSize 
		{ 
			get{return _receiveBufferSize;} 
			set{_receiveBufferSize=value;} 
		} 
		public int SendBufferSize 
		{ 
			get{return _sendBufferSize;} 
			set{_sendBufferSize=value;} 
		} 
 
		private void WaitForResponse(bool blnCondiction, int intInterval) 
		{ 
			if(intInterval==0) 
				intInterval=WaitForResponseInterval; 
			while(!blnCondiction==true) 
			{ 
				Thread.Sleep(intInterval); 
			} 
		} 
 
		private void WaitForResponse(ref StreamReader rdReader, int intInterval) 
		{ 
			if(intInterval==0) 
				intInterval=WaitForResponseInterval; 
			while(!rdReader.BaseStream.CanRead) 
			{ 
				Thread.Sleep(intInterval); 
			} 
		} 
 
		private void WaitForResponse(ref StreamReader rdReader) 
		{ 
			DateTime dtStart=DateTime.Now; 
			TimeSpan tsSpan; 
			while(!rdReader.BaseStream.CanRead) 
			{ 
				tsSpan=DateTime.Now.Subtract(dtStart); 
				if(tsSpan.Milliseconds>_receiveTimeOut) 
					break; 
				Thread.Sleep(_waitForResponseInterval); 
			} 
		} 
 
		private void WaitForResponse(ref StreamWriter wrWriter, int intInterval) 
		{ 
			if(intInterval==0) 
				intInterval=WaitForResponseInterval; 
			while(!wrWriter.BaseStream.CanWrite) 
			{ 
				Thread.Sleep(intInterval); 
			} 
		} 
		private void ExtractApopTimestamp(string strResponse) 
		{ 
			Match match = Regex.Match(strResponse, "<.+>"); 
			if (match.Success) 
			{ 
				_aPOPTimestamp = match.Value; 
			} 
		} 
		private bool IsOkResponse(string strResponse) 
		{ 
			return (strResponse.Substring(0, 3) == RESPONSE_OK); 
		} 
		private string GetResponseContent() 
		{ 
			return _lastCommandResponse.Substring(3); 
		} 
		private bool SendCommand(string strCommand, bool blnSilent) 
		{ 
			_lastCommandResponse = ""; 
			try 
			{ 
				if(writer.BaseStream.CanWrite) 
				{ 
					writer.WriteLine(strCommand); 
					writer.Flush(); 
					WaitForResponse(ref reader); 
					_lastCommandResponse = reader.ReadLine();				 
					return IsOkResponse(_lastCommandResponse); 
				} 
				else 
					return false; 
			} 
			catch(Exception e) 
			{ 
				if(!blnSilent) 
				{ 
					_Error = strCommand + ":" +e.Message; 
					Utility.LogError(_Error); 
				} 
				return false; 
			} 
		} 
		private bool SendCommand(string strCommand) 
		{ 
			return SendCommand(strCommand,false); 
		} 
 
		private int SendCommandIntResponse(string strCommand) 
		{ 
			int retVal = 0; 
			if(SendCommand(strCommand)) 
			{ 
				try 
				{ 
					retVal = int.Parse(_lastCommandResponse.Split(' ')[1]); 
				} 
				catch(Exception e) 
				{ 
					Utility.LogError(strCommand + ":" + e.Message); 
				} 
			} 
			return retVal; 
		} 
		public POPClient() 
		{ 
			Utility.Log=false; 
		}		 
		public POPClient(string strHost,int intPort,string strlogin,string strPassword,AuthenticationMethod authenticationMethod) 
		{ 
			Connect(strHost, intPort); 
			Authenticate(strlogin,strPassword,authenticationMethod); 
		} 
 
		public void Connect(string strHost,int intPort) 
		{ 
			OnCommunicationBegan(EventArgs.Empty); 
 
			clientSocket=new TcpClient(); 
			clientSocket.ReceiveTimeout=_receiveTimeOut; 
			clientSocket.SendTimeout=_sendTimeOut; 
			clientSocket.ReceiveBufferSize=_receiveBufferSize; 
			clientSocket.SendBufferSize=_sendBufferSize; 
 
			try 
			{ 
				clientSocket.Connect(strHost,intPort);				 
			} 
			catch(SocketException e) 
			{				 
				Disconnect(); 
				Utility.LogError("Connect():"+e.Message); 
				throw new PopServerNotFoundException(); 
			} 
 
			reader=new StreamReader(clientSocket.GetStream(),Encoding.Default,true); 
			writer=new StreamWriter(clientSocket.GetStream()); 
			writer.AutoFlush=true; 
		 
			WaitForResponse(ref reader,WaitForResponseInterval); 
 
			string strResponse=reader.ReadLine(); 
 
			if(IsOkResponse(strResponse)) 
			{ 
				ExtractApopTimestamp(strResponse); 
				_connected=true; 
				OnCommunicationOccured(EventArgs.Empty); 
			} 
			else 
			{ 
				Disconnect(); 
				Utility.LogError("Connect():"+"Error when login, maybe POP3 server not exist"); 
				throw new PopServerNotAvailableException(); 
			} 
		} 
		public void Disconnect() 
		{ 
			try 
			{ 
				clientSocket.ReceiveTimeout=500; 
				clientSocket.SendTimeout=500; 
				SendCommand("QUIT",true); 
				clientSocket.ReceiveTimeout=_receiveTimeOut; 
				clientSocket.SendTimeout=_sendTimeOut; 
				reader.Close(); 
				writer.Close(); 
				clientSocket.GetStream().Close(); 
				clientSocket.Close(); 
			} 
			catch 
			{ 
				//Utility.LogError("Disconnect():"+e.Message); 
			} 
			finally 
			{ 
				reader=null; 
				writer=null; 
				clientSocket=null; 
			} 
			OnCommunicationLost(EventArgs.Empty); 
		} 
 
		~POPClient() 
		{ 
			Disconnect(); 
		} 
		public void Authenticate(string strlogin,string strPassword) 
		{ 
			Authenticate(strlogin,strPassword,AuthenticationMethod.USERPASS); 
		} 
		public void Authenticate(string strlogin,string strPassword,AuthenticationMethod authenticationMethod) 
		{ 
			if(authenticationMethod==AuthenticationMethod.USERPASS) 
			{ 
				AuthenticateUsingUSER(strlogin,strPassword);				 
			} 
			else if(authenticationMethod==AuthenticationMethod.APOP) 
			{ 
				AuthenticateUsingAPOP(strlogin,strPassword); 
			} 
			else if(authenticationMethod==AuthenticationMethod.TRYBOTH) 
			{ 
				try 
				{ 
					AuthenticateUsingUSER(strlogin,strPassword); 
				} 
				catch(InvalidLoginException e) 
				{ 
					Utility.LogError("Authenticate():"+e.Message); 
				} 
				catch(InvalidPasswordException e) 
				{ 
					Utility.LogError("Authenticate():"+e.Message); 
				} 
				catch(Exception e) 
				{ 
					Utility.LogError("Authenticate():"+e.Message); 
					AuthenticateUsingAPOP(strlogin,strPassword); 
				} 
			} 
		} 
		private void AuthenticateUsingUSER(string strlogin,string strPassword) 
		{				 
			OnAuthenticationBegan(EventArgs.Empty); 
 
			if(!SendCommand("USER " + strlogin)) 
			{ 
				Utility.LogError("AuthenticateUsingUSER():wrong user"); 
				throw new InvalidLoginException(); 
			} 
			 
			WaitForResponse(ref writer,WaitForResponseInterval); 
 
			if(!SendCommand("PASS " + strPassword))	 
			{ 
				if(_lastCommandResponse.ToLower().IndexOf("lock")!=-1) 
				{ 
					Utility.LogError("AuthenticateUsingUSER():maildrop is locked"); 
					throw new PopServerLockException();			 
				} 
				else 
				{ 
					Utility.LogError("AuthenticateUsingUSER():wrong password or " + GetResponseContent()); 
					throw new InvalidPasswordException(); 
				} 
			} 
			 
			OnAuthenticationFinished(EventArgs.Empty); 
		} 
		private void AuthenticateUsingAPOP(string strlogin,string strPassword) 
		{ 
			OnAuthenticationBegan(EventArgs.Empty); 
 
			if(!SendCommand("APOP " + strlogin + " " + MyMD5.GetMD5HashHex(strPassword))) 
			{ 
				Utility.LogError("AuthenticateUsingAPOP():wrong user or password"); 
				throw new InvalidLoginOrPasswordException();		 
			} 
 
			OnAuthenticationFinished(EventArgs.Empty); 
		} 
		private string[] GetParameters(string input) 
		{ 
			string []temp=input.Split(' '); 
			string []retStringArray=new string[temp.Length-1]; 
			Array.Copy(temp,1,retStringArray,0,temp.Length-1); 
 
			return retStringArray; 
		}		 
		public int GetMessageCount() 
		{			 
			return SendCommandIntResponse("STAT"); 
		} 
		public bool DeleteMessage(int intMessageIndex)  
		{ 
			return SendCommand("DELE " + intMessageIndex.ToString()); 
		} 
		public bool DeleteAllMessages()  
		{ 
			int messageCount=GetMessageCount(); 
			for(int messageItem=messageCount;messageItem>0;messageItem--) 
			{ 
				if (!DeleteMessage(messageItem)) 
					return false; 
			} 
			return true; 
		} 
		public bool QUIT() 
		{ 
			return SendCommand("QUIT"); 
		} 
		public bool NOOP() 
		{ 
			return SendCommand("NOOP"); 
		} 
		public bool RSET() 
		{ 
			return SendCommand("RSET"); 
		} 
		public bool USER() 
		{ 
			return SendCommand("USER"); 
 
		} 
		public MIMEParser.Message GetMessageHeader(int intMessageNumber) 
		{ 
			OnMessageTransferBegan(EventArgs.Empty); 
 
			MIMEParser.Message msg=FetchMessage("TOP "+intMessageNumber.ToString()+" 0", true); 
			 
			OnMessageTransferFinished(EventArgs.Empty); 
 
			return msg; 
		} 
		public string GetMessageUID(int intMessageNumber) 
		{ 
			string[] strValues=null; 
			if(SendCommand("UIDL " + intMessageNumber.ToString())) 
			{ 
				strValues = GetParameters(_lastCommandResponse); 
			} 
			return strValues[1];			 
		} 
		public ArrayList GetMessageUIDs() 
		{ 
			ArrayList uids=new ArrayList(); 
			if(SendCommand("UIDL")) 
			{ 
				string strResponse=reader.ReadLine(); 
				while (strResponse!=".") 
				{ 
					uids.Add(strResponse.Split(' ')[1]); 
					strResponse=reader.ReadLine(); 
				} 
				return uids; 
			} 
			else 
			{ 
				return null; 
			} 
		} 
		public ArrayList LIST() 
		{ 
			ArrayList sizes=new ArrayList(); 
			if(SendCommand("LIST")) 
			{ 
				string strResponse=reader.ReadLine(); 
				while (strResponse!=".") 
				{ 
					sizes.Add(int.Parse(strResponse.Split(' ')[1])); 
					strResponse=reader.ReadLine(); 
				} 
				return sizes; 
			} 
			else 
			{ 
				return null; 
			} 
		} 
		public int LIST(int intMessageNumber) 
		{ 
			return SendCommandIntResponse("LIST " + intMessageNumber.ToString()); 
		} 
		private string ReceiveContent(int intContentLength) 
		{ 
			string strResponse=null; 
			StringBuilder builder = new StringBuilder(); 
			 
			WaitForResponse(ref reader,WaitForResponseInterval); 
 
			strResponse = reader.ReadLine(); 
			int intLines=0; 
			int intLen=0; 
 
			while (strResponse!=".") 
			{ 
				builder.Append(strResponse + "\r\n"); 
				intLines+=1; 
				intLen+=strResponse.Length+"\r\n".Length; 
				 
				WaitForResponse(ref reader,1); 
 
				strResponse = reader.ReadLine(); 
				if((intLines % _receiveContentSleepInterval)==0) //make an interval pause to ensure response from server 
					Thread.Sleep(1); 
			} 
 
			builder.Append(strResponse+ "\r\n"); 
 
			return builder.ToString(); 
 
		} 
		public MIMEParser.Message GetMessage(int intNumber, bool blnOnlyHeader) 
		{			 
			OnMessageTransferBegan(EventArgs.Empty); 
 
			MIMEParser.Message msg=FetchMessage("RETR " + intNumber.ToString(), blnOnlyHeader); 
 
			OnMessageTransferFinished(EventArgs.Empty); 
 
			return msg; 
		} 
		public MIMEParser.Message FetchMessage(string strCommand, bool blnOnlyHeader) 
		{			 
			_receiveFinish=false; 
			if(!SendCommand(strCommand))			 
				return null; 
 
			try 
			{ 
				string receivedContent=ReceiveContent(-1); 
 
				MIMEParser.Message msg=new MIMEParser.Message(ref _receiveFinish,_basePath,_autoDecodeMSTNEF,receivedContent,blnOnlyHeader); 
 
				WaitForResponse(_receiveFinish,WaitForResponseInterval); 
 
				return msg; 
			} 
			catch(Exception e) 
			{ 
				Utility.LogError("FetchMessage():"+e.Message); 
				return null; 
			} 
		} 
 
	} 
}