Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C# » General » Downloads
 
Add your own
alternative version
Go to top

SIP Stack with SIP Proxy - (VOIP)

, 11 Jun 2007
C# implementation of SIP
SIP_Proxy_demo.zip
SIP_Proxy_demo
SIP_Proxy_demo.suo
SIP_Proxy_demo
bin
Debug
LumiSoft.Net.dll
SIP_Proxy_demo.exe
SIP_Proxy_demo.vshost.exe
dep
LumiSoft.Net.dll
LumiSoft.Net.pdb
Properties
Settings.settings
Resources
add.ico
app.ico
delete.ico
edit.ico
error.ico
info.ico
refresh.ico
rule.ico
server_running.ico
server_stopped.ico
viewmessages.ico
Stack.zip
Net
docs
dns
dns_records.jpg
dns_records.vsd
Net
_junk
_Obsolete
AUTH
bin
Release
LumiSoft.Net.dll
Data
Dns
Client
FTP
Client
Server
HTTP
Server
ICMP
IMAP
Client
Server
IO
Log
LumiSoft.Net
Mime
vCard
Net.csproj.user
Net.suo
NNTP
Client
POP3
Client
Server
RTP
SDP
ServersCore
SIP
Client
Message
Proxy
Stack
SMTP
Client
Server
STUN
Client
Message
URI
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Security.Cryptography;

namespace LumiSoft.Net.POP3.Client
{
	/// <summary>
	/// POP3 Client.
	/// </summary>
	/// <example>
	/// <code>
	/// 
	/// /*
	///  To make this code to work, you need to import following namespaces:
	///  using LumiSoft.Net.Mime;
	///  using LumiSoft.Net.POP3.Client; 
	///  */
	/// 
	/// using(POP3_Client c = new POP3_Client()){
	///		c.Connect("ivx",110);
	///		c.Authenticate("test","test",true);
	///		
	///		POP3_MessagesInfo mInf = c.GetMessagesInfo();
	///		
	///		// Get first message if there is any
	///		if(c.Messages.Count > 0){
	///			// Do your suff
	///			
	///			// Parse message
	///			Mime m = Mime.Parse(c.Messages[0].MessageToByte());
	///			string from = m.MainEntity.From;
	///			string subject = m.MainEntity.Subject;			
	///			// ... 
	///		}		
	///	}
	/// </code>
	/// </example>
	public class POP3_Client : IDisposable
	{
		private SocketEx               m_pSocket         = null;
		private SocketLogger           m_pLogger         = null;
		private bool                   m_Connected       = false;
		private bool                   m_Authenticated   = false;
		private string                 m_ApopHashKey     = "";
		private bool                   m_LogCmds         = false;
        private bool                   m_IsUidlSupported = false;
        private POP3_MessageCollection m_pMessages       = null;

		/// <summary>
		/// Occurs when POP3 session has finished and session log is available.
		/// </summary>
		public event LogEventHandler SessionLog = null;

		/// <summary>
		/// Default constructor.
		/// </summary>
		public POP3_Client()
		{				
		}

		#region method Dispose

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		public void Dispose()
		{
			try{
				Disconnect();
			}
			catch{
			}
		}

		#endregion


		#region method Connect

        /// <summary>
		/// Connects to specified host.
		/// </summary>
		/// <param name="host">Host name.</param>
		/// <param name="port">Port number. Default POP3 port is 110.</param>
		public void Connect(string host,int port)
		{
            Connect(host,port,false);
        }

		/// <summary>
		/// Connects to specified host.
		/// </summary>
		/// <param name="host">Host name.</param>
		/// <param name="port">Port number. Default POP3 port is 110 and SSL port is 995.</param>
        /// <param name="ssl">Specifies if to connected via SSL.</param>
		public void Connect(string host,int port,bool ssl)
		{
			if(!m_Connected){
                SocketEx s = new SocketEx();
                s.Connect(host,port,ssl);
                m_pSocket = s;

				if(m_LogCmds && SessionLog != null){
					m_pLogger = new SocketLogger(s.RawSocket,SessionLog);
					m_pLogger.SessionID = Guid.NewGuid().ToString();
					m_pSocket.Logger = m_pLogger;
				}

				// Set connected flag
				m_Connected = true;

				string reply = m_pSocket.ReadLine();
				if(reply.StartsWith("+OK")){
					// Try to read APOP hash key, if supports APOP
					if(reply.IndexOf("<") > -1 && reply.IndexOf(">") > -1){
						m_ApopHashKey = reply.Substring(reply.LastIndexOf("<"),reply.LastIndexOf(">") - reply.LastIndexOf("<") + 1);
					}
				}
			}
		}

		#endregion

		#region method Disconnect

		/// <summary>
		/// Closes connection to POP3 server.
		/// </summary>
		public void Disconnect()
		{
			try{
				if(m_pSocket != null){
					// Send QUIT
					m_pSocket.WriteLine("QUIT");			

					m_pSocket.Shutdown(SocketShutdown.Both);					
				}
			}
			catch{
			}
                        
			if(m_pLogger != null){
				m_pLogger.Flush();
			}
			m_pLogger = null;

            m_pMessages     = null;
			m_pSocket       = null;
			m_Connected     = false;			
			m_Authenticated = false;
		}

		#endregion

        #region method StartTLS

        /// <summary>
        /// Switches POP3 connection to SSL.
        /// </summary>
        public void StartTLS()
        {
            /* RFC 2595 4. POP3 STARTTLS extension.
                Arguments: none

                Restrictions:
                    Only permitted in AUTHORIZATION state.
             
                Possible Responses:
                     +OK -ERR

                 Examples:
                     C: STLS
                     S: +OK Begin TLS negotiation
                     <TLS negotiation, further commands are under TLS layer>
                       ...
                     C: STLS
                     S: -ERR Command not permitted when TLS active
            */

            if(!m_Connected){
				throw new Exception("You must connect first !");
			}
			if(m_Authenticated){
				throw new Exception("The STLS command is only valid in non-authenticated state !");
			}
            if(m_pSocket.SSL){
                throw new Exception("Connection is already secure !");
            }

            m_pSocket.WriteLine("STLS");

            string reply = m_pSocket.ReadLine();
			if(!reply.ToUpper().StartsWith("+OK")){
				throw new Exception("Server returned:" + reply);
			}

            m_pSocket.SwitchToSSL_AsClient();
        }

        #endregion

		#region method Authenticate

		/// <summary>
		/// Authenticates user.
		/// </summary>
		/// <param name="userName">User login name.</param>
		/// <param name="password">Password.</param>
		/// <param name="tryApop"> If true and POP3 server supports APOP, then APOP is used, otherwise normal login used.</param>
		public void Authenticate(string userName,string password,bool tryApop)
		{
			if(!m_Connected){
				throw new Exception("You must connect first !");
			}
			if(m_Authenticated){
				throw new Exception("You are already authenticated !");
			}

			// Supports APOP, use it
			if(tryApop && m_ApopHashKey.Length > 0){
				//--- Compute md5 hash -----------------------------------------------//
				byte[] data = System.Text.Encoding.ASCII.GetBytes(m_ApopHashKey + password);
			
				MD5 md5 = new MD5CryptoServiceProvider();			
				byte[] hash = md5.ComputeHash(data);

				string hexHash = BitConverter.ToString(hash).ToLower().Replace("-","");
				//---------------------------------------------------------------------//

				m_pSocket.WriteLine("APOP " + userName + " " + hexHash);

				string reply = m_pSocket.ReadLine();
				if(reply.StartsWith("+OK")){
					m_Authenticated = true;
				}
				else{
					throw new Exception("Server returned:" + reply);
				}
			}
			else{ // Use normal LOGIN, don't support APOP 
				m_pSocket.WriteLine("USER " + userName);

				string reply = m_pSocket.ReadLine();
				if(reply.StartsWith("+OK")){
					m_pSocket.WriteLine("PASS " + password);

					reply = m_pSocket.ReadLine();
					if(reply.StartsWith("+OK")){
						m_Authenticated = true;
					}
					else{
						throw new Exception("Server returned:" + reply);
					}
				}
				else{
					throw new Exception("Server returned:" + reply);
				}				
			}

            if(m_Authenticated){
                FillsMessages();
            }

            if(m_Authenticated && m_pSocket.Logger != null){
                m_pSocket.Logger.UserName = userName;
            }
		}

		#endregion
  // ??? will reset restore marked for deletion flag ????      
        #region method Reset

		/// <summary>
		/// Resets session.
		/// </summary>
		public void Reset()
		{
			if(!m_Connected){
				throw new Exception("You must connect first !");
			}

			if(!m_Authenticated){
				throw new Exception("You must authenticate first !");
			}

			m_pSocket.WriteLine("RSET");

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(!line.StartsWith("+OK")){
				throw new Exception("Server returned:" + line);
			}
		}

		#endregion


    // Obsolete
		#region function GetMessagesInfo

		/// <summary>
		/// Gets messages info.
		/// </summary>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
		public POP3_MessagesInfo GetMessagesInfo()
		{
			if(!m_Connected){
				throw new Exception("You must connect first !");
			}

			if(!m_Authenticated){
				throw new Exception("You must authenticate first !");
			}

			POP3_MessagesInfo messagesInfo = new POP3_MessagesInfo();

			// Before getting list get UIDL list, then we can make full message info (UID,No,Size).
			Hashtable uidlList = GetUidlList();

			m_pSocket.WriteLine("LIST");

			/* NOTE: If reply is +OK, this is multiline respone and is terminated with '.'.
			Examples:
				C: LIST
				S: +OK 2 messages (320 octets)
				S: 1 120				
				S: 2 200
				S: .
				...
				C: LIST 3
				S: -ERR no such message, only 2 messages in maildrop
			*/

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){
				// Read lines while get only '.' on line itshelf.
				while(true){
					line = m_pSocket.ReadLine();

					// End of data
					if(line.Trim() == "."){
						break;
					}
					else{
						string[] param = line.Trim().Split(new char[]{' '});
						int  no   = Convert.ToInt32(param[0]);
						long size = Convert.ToInt64(param[1]);

						messagesInfo.Add(uidlList[no].ToString(),no,size);
					}
				}
			}
			else{
				throw new Exception("Server returned:" + line);
			}

			return messagesInfo;
		}

		#endregion
    // Obsolete
		#region function GetUidlList

		/// <summary>
		/// Gets uid listing.
		/// </summary>
		/// <returns>Returns Hashtable containing uidl listing. Key column contains message NR and value contains message UID.</returns>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
		public Hashtable GetUidlList()
		{
			if(!m_Connected){
				throw new Exception("You must connect first !");
			}

			if(!m_Authenticated){
				throw new Exception("You must authenticate first !");
			}

			Hashtable retVal = new Hashtable();

			m_pSocket.WriteLine("UIDL");

			/* NOTE: If reply is +OK, this is multiline respone and is terminated with '.'.
			Examples:
				C: UIDL
				S: +OK
				S: 1 whqtswO00WBw418f9t5JxYwZ
				S: 2 QhdPYR:00WBw1Ph7x7
				S: .
				...
				C: UIDL 3
				S: -ERR no such message
			*/

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){
				// Read lines while get only '.' on line itshelf.				
				while(true){
					line = m_pSocket.ReadLine();

					// End of data
					if(line.Trim() == "."){
						break;
					}
					else{
						string[] param = line.Trim().Split(new char[]{' '});
						int    nr  = Convert.ToInt32(param[0]);
						string uid = param[1];

						retVal.Add(nr,uid);
					}
				}
			}
			else{
				throw new Exception("Server returned:" + line);
			}

			return retVal;
		}

		#endregion
    // Obsolete
		#region method GetMessage

		/// <summary>
		/// Gets specified message.
		/// </summary>
		/// <param name="msgInfo">Pop3 message info of message what to get.</param>
		/// <returns></returns>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
		public byte[] GetMessage(POP3_MessageInfo msgInfo)
		{
			return GetMessage(msgInfo.MessageNumber);
		}

		/// <summary>
		/// Gets specified message.
		/// </summary>
		/// <param name="messageNo">Message number.</param>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
		public byte[] GetMessage(int messageNo)
		{
            MemoryStream stream = new MemoryStream();
			GetMessage(messageNo,stream);
            return stream.ToArray();
		}

        /// <summary>
        /// Gets specified message and stores it to specified stream.
        /// </summary>
        /// <param name="messageNo">Message number.</param>
        /// <param name="stream">Stream where to store message.</param>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
        public void GetMessage(int messageNo,Stream stream)
		{
            if(!m_Connected){
				throw new Exception("You must connect first !");
			}

			if(!m_Authenticated){
				throw new Exception("You must authenticate first !");
			}

			m_pSocket.WriteLine("RETR " + messageNo.ToString());

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){    
                m_pSocket.ReadPeriodTerminated(stream,100000000);
			}
			else{
				throw new Exception("Server returned:" + line);
			}
        }

		#endregion
    // Obsolete
		#region method DeleteMessage

		/// <summary>
		/// Deletes specified message
		/// </summary>
		/// <param name="messageNr">Message number.</param>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
		public void DeleteMessage(int messageNr)
		{
			if(!m_Connected){
				throw new Exception("You must connect first !");
			}

			if(!m_Authenticated){
				throw new Exception("You must authenticate first !");
			}

			m_pSocket.WriteLine("DELE " + messageNr.ToString());

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(!line.StartsWith("+OK")){
				throw new Exception("Server returned:" + line);
			}
		}

		#endregion
    // Obsolete
		#region method GetTopOfMessage

		/// <summary>
		/// Gets top lines of message.
		/// </summary>
		/// <param name="nr">Message number which top lines to get.</param>
		/// <param name="nLines">Number of lines to get.</param>
        [Obsolete("Will be removed soon, use this.Messages instead !")]
		public byte[] GetTopOfMessage(int nr,int nLines)
		{
			if(!m_Connected){
				throw new Exception("You must connect first !");
			}

			if(!m_Authenticated){
				throw new Exception("You must authenticate first !");
			}
			

			m_pSocket.WriteLine("TOP " + nr.ToString() + " " + nLines.ToString());

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){
				MemoryStream strm = new MemoryStream();
                m_pSocket.ReadPeriodTerminated(strm,100000000);

                return strm.ToArray();
			}
			else{
				throw new Exception("Server returned:" + line);
			}
		}

		#endregion


        #region method MarkMessageForDeletion

        /// <summary>
        /// Marks specified message for deletion.
        /// </summary>
        /// <param name="sequenceNumber">Message sequence number.</param>
        internal void MarkMessageForDeletion(int sequenceNumber)
        {
            m_pSocket.WriteLine("DELE " + sequenceNumber.ToString());

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(!line.StartsWith("+OK")){
				throw new Exception("Server returned:" + line);
			}
        }

        #endregion

        #region method GetMessageI

        /// <summary>
        /// Stores specified message to the specified stream.
        /// </summary>
        /// <param name="sequenceNumber">Message 1 based sequence number.</param>
        /// <param name="stream">Stream where to store message.</param>
        internal void GetMessageI(int sequenceNumber,Stream stream)
        {
            m_pSocket.WriteLine("RETR " + sequenceNumber.ToString());

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){    
                m_pSocket.ReadPeriodTerminated(stream,100000000);
			}
			else{
				throw new Exception("Server returned:" + line);
			}
        }

        #endregion

        #region method GetTopOfMessage

        /// <summary>
        /// Stores specified message header + specified lines of body to the specified stream.
        /// </summary>
        /// <param name="sequenceNumber">Message 1 based sequence number.</param>
        /// <param name="stream">Stream where to store data.</param>
        /// <param name="lineCount">Number of lines of message body to get.</param>
        internal void GetTopOfMessage(int sequenceNumber,Stream stream,int lineCount)
        {
            m_pSocket.WriteLine("TOP " + sequenceNumber.ToString() + " " + lineCount.ToString());

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){
				MemoryStream strm = new MemoryStream();
                m_pSocket.ReadPeriodTerminated(strm,100000000);
			}
			else{
				throw new Exception("Server returned:" + line);
			}
        }

        #endregion


        #region method FillsMessages

        /// <summary>
        /// Fills messages info.
        /// </summary>
        private void FillsMessages()
        {
            m_pMessages = new POP3_MessageCollection();

            /*
                First make messages info, then try to add UIDL if server supports.
            */
                                   
			/* NOTE: If reply is +OK, this is multiline respone and is terminated with '.'.
			Examples:
				C: LIST
				S: +OK 2 messages (320 octets)
				S: 1 120				
				S: 2 200
				S: .
				...
				C: LIST 3
				S: -ERR no such message, only 2 messages in maildrop
			*/

            m_pSocket.WriteLine("LIST");

			// Read first line of reply, check if it's ok
			string line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){
				// Read lines while get only '.' on line itshelf.
				while(true){
					line = m_pSocket.ReadLine();

					// End of data
					if(line.Trim() == "."){
						break;
					}
					else{
                        string[] no_size = line.Trim().Split(new char[]{' '});
                        m_pMessages.Add(Convert.ToInt32(no_size[1]));
					}
				}
			}
			else{
				throw new Exception("Server returned:" + line);
			}

            // Try to fill messages UIDs.
            /* NOTE: If reply is +OK, this is multiline respone and is terminated with '.'.
			Examples:
				C: UIDL
				S: +OK
				S: 1 whqtswO00WBw418f9t5JxYwZ
				S: 2 QhdPYR:00WBw1Ph7x7
				S: .
				...
				C: UIDL 3
				S: -ERR no such message
			*/

            m_pSocket.WriteLine("UIDL");

			// Read first line of reply, check if it's ok
			line = m_pSocket.ReadLine();
			if(line.StartsWith("+OK")){
                m_IsUidlSupported = true;

				// Read lines while get only '.' on line itshelf.
				while(true){
					line = m_pSocket.ReadLine();

					// End of data
					if(line.Trim() == "."){
						break;
					}
					else{
                        string[] no_uid = line.Trim().Split(new char[]{' '});                        
                        m_pMessages[Convert.ToInt32(no_uid[0]) - 1].SetUID(no_uid[1]);
					}
				}
			}
			else{
				m_IsUidlSupported = false;
			}
        }

        #endregion


        #region Properties Implementation

        /// <summary>
		/// Gets if POP3 client is connected.
		/// </summary>
		public bool Connected
		{
			get{ return m_Connected; }
		}

		/// <summary>
		/// Gets if pop3 client is authenticated.
		/// </summary>
		public bool Authenticated
		{
			get{ return m_Authenticated; }
		}

		/// <summary>
		/// Gets or sets if to log commands.
		/// </summary>
		public bool LogCommands
		{
			get{ return m_LogCmds;	}

			set{ m_LogCmds = value; }
		}
        
        /// <summary>
        /// Gets if the connection is an SSL connection.
        /// </summary>
        /// <exception cref="InvalidOperationException">Is raised when this property is accessed and 
        /// POP3 client is not connected.</exception>
        public bool IsSecureConnection
        {
            get{ 
                if(!m_Connected){
				    throw new InvalidOperationException("You must connect first");
			    }

                return m_pSocket.SSL; 
            }
        }

        /// <summary>
        /// Gets if POP3 server supports UIDL command.
        /// </summary>
        /// <exception cref="InvalidOperationException">Is raised when this property is accessed and 
        /// POP3 client is not connected and authenticated.</exception>
        public bool IsUidlSupported
        {
            get{ 
                if(!m_Connected){
				    throw new InvalidOperationException("You must connect first");
			    }
                if(!m_Authenticated){
				    throw new InvalidOperationException("You must authenticate first !");
			    }

                return m_IsUidlSupported; 
            }
        }

        /// <summary>
        /// Gets messages collection.
        /// </summary>
        /// <exception cref="InvalidOperationException">Is raised when this property is accessed and 
        /// POP3 client is not connected and authenticated.</exception>
        public POP3_MessageCollection Messages
        {
            get{ 
                if(!m_Connected){
				    throw new InvalidOperationException("You must connect first");
			    }
                if(!m_Authenticated){
				    throw new InvalidOperationException("You must authenticate first !");
			    }

                return m_pMessages; 
            }
        }

		#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)

Share

About the Author

Ivar Lumi

Estonia Estonia
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 11 Jun 2007
Article Copyright 2007 by Ivar Lumi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid