/////////////////////////////////////////////
// 類名:Pop3 //
// 功能:接收電子郵件 ///////////////////////////////////////////////
using System;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.IO;
namespace ZTSX.Email
{
/// <summary>
/// Pop3 的摘要說明。
/// </summary>
public class Pop3
{
private string mstrHost = null; //主機名稱或IP地址
private int mintPort = 110; //主機的端口號(默認為110)
private TcpClient mtcpClient = null; //客戶端
private NetworkStream mnetStream = null; //網絡基礎數據流
private StreamReader m_stmReader = null; //讀取字節流
private string mstrStatMessage = null; //執行STAT命令后得到的消息(從中得到郵件數)
/// <summary>
/// 構造函數
/// </summary>
/// <remarks>一個郵件接收對象</remarks>
public Pop3()
{
}
/// <summary>
/// 構造函數
/// </summary>
/// <param name="host">主機名稱或IP地址</param>
public Pop3(string host)
{
mstrHost = host;
}
/// <summary>
/// 構造函數
/// </summary>
/// <param name="host">主機名稱或IP地址</param>
/// <param name="port">主機的端口號</param>
/// <remarks>一個郵件接收對象</remarks>
public Pop3(string host,int port)
{
mstrHost = host;
mintPort = port;
}
#region 屬性
/// <summary>
/// 主機名稱或IP地址
/// </summary>
/// <remarks>主機名稱或IP地址</remarks>
public string HostName
{
get{return mstrHost;}
set{mstrHost = value;}
}
/// <summary>
/// 主機的端口號
/// </summary>
/// <remarks>主機的端口號</remarks>
public int Port
{
get{return mintPort;}
set{mintPort = value;}
}
#endregion
#region 私有方法
/// <summary>
/// 向網絡訪問的基礎數據流中寫數據(發送命令碼)
/// </summary>
/// <param name="netStream">可以用於網絡訪問的基礎數據流</param>
/// <param name="command">命令行</param>
/// <remarks>向網絡訪問的基礎數據流中寫數據(發送命令碼)</remarks>
private void WriteToNetStream(ref NetworkStream netStream,String command)
{
string strToSend = command + "/r/n";
byte[] arrayToSend = System.Text.Encoding.ASCII.GetBytes(strToSend.ToCharArray());
netStream.Write(arrayToSend,0,arrayToSend.Length);
}
/// <summary>
/// 檢查命令行結果是否正確
/// </summary>
/// <param name="message">命令行的執行結果</param>
/// <param name="check">正確標志</param>
/// <returns>
/// 類型:布爾
/// 內容:true表示沒有錯誤,false為有錯誤
/// </returns>
/// <remarks>檢查命令行結果是否有錯誤</remarks>
private bool CheckCorrect(string message,string check)
{
if(message.IndexOf(check) == -1)
return false;
else
return true;
}
/// <summary>
/// 郵箱中的未讀郵件數
/// </summary>
/// <param name="message">執行完LIST命令后的結果</param>
/// <returns>
/// 類型:整型
/// 內容:郵箱中的未讀郵件數
/// </returns>
/// <remarks>郵箱中的未讀郵件數</remarks>
private int GetMailNumber(string message)
{
string[] strMessage = message.Split(' ');
return Int32.Parse(strMessage[1]);
}
/// <summary>
/// 得到經過解碼后的郵件的內容
/// </summary>
/// <param name="encodingContent">解碼前的郵件的內容</param>
/// <returns>
/// 類型:字符串
/// 內容:解碼后的郵件的內容
/// </returns>
/// <remarks>得到解碼后的郵件的內容</remarks>
private string GetDecodeMailContent(string encodingContent)
{
string strContent = encodingContent.Trim();
string strEncode = null;
int iStart = strContent.IndexOf("Base64");
if(iStart == -1)
throw new Pop3Exception("郵件內容不是Base64編碼,請檢查");
else
{
strEncode = strContent.Substring(iStart + 6,strContent.Length - iStart - 6);
try
{
return SX.Encode.TransformToString(strEncode);
}
catch(SX.EncodeException exc)
{
throw new Pop3Exception(exc.Message);
}
}
}
#endregion
/// <summary>
/// 與主機建立連接
/// </summary>
/// <returns>
/// 類型:布爾
/// 內容:連接結果(true為連接成功,false為連接失敗)
/// </returns>
/// <remarks>與主機建立連接</remarks>
public bool Connect()
{
if(mstrHost == null)
throw new Exception("請提供SMTP主機名稱或IP地址!");
if(mintPort == 0)
throw new Exception("請提供SMTP主機的端口號");
try
{
mtcpClient = new TcpClient(mstrHost,mintPort);
mnetStream = mtcpClient.GetStream();
m_stmReader = new StreamReader(mtcpClient.GetStream());
string strMessage = m_stmReader.ReadLine();
if(CheckCorrect(strMessage,"+OK") == true)
return true;
else
return false;
}
catch(SocketException exc)
{
throw new Pop3Exception(exc.ToString());
}
catch(NullReferenceException exc)
{
throw new Pop3Exception(exc.ToString());
}
}
#region Pop3命令
/// <summary>
/// 執行Pop3命令,並檢查執行的結果
/// </summary>
/// <param name="command">Pop3命令行</param>
/// <returns>
/// 類型:字符串
/// 內容:Pop3命令的執行結果
/// </returns>
private string ExecuteCommand(string command)
{
string strMessage = null; //執行Pop3命令后返回的消息
try
{
//發送命令
WriteToNetStream(ref mnetStream,command);
//讀取多行
if(command.Substring(0,4).Equals("LIST") || command.Substring(0,4).Equals("RETR") || command.Substring(0,4).Equals("UIDL")) //記錄STAT后的消息(其中包含郵件數)
{
strMessage = ReadMultiLine();
if(command.Equals("LIST")) //記錄LIST后的消息(其中包含郵件數)
mstrStatMessage = strMessage;
}
//讀取單行
else
strMessage = m_stmReader.ReadLine();
//判斷執行結果是否正確
if(CheckCorrect(strMessage,"+OK"))
return strMessage;
else
return "Error";
}
catch(IOException exc)
{
throw new Pop3Exception(exc.ToString());
}
}
/// <summary>
/// 在Pop3命令中,LIST、RETR和UIDL命令的結果要返回多行,以點號(.)結尾,
/// 所以如果想得到正確的結果,必須讀取多行
/// </summary>
/// <returns>
/// 類型:字符串
/// 內容:執行Pop3命令后的結果
/// </returns>
private string ReadMultiLine()
{
string strMessage = m_stmReader.ReadLine();
string strTemp = null;
while(strMessage != ".")
{
strTemp = strTemp + strMessage;
strMessage = m_stmReader.ReadLine();
}
return strTemp;
}
//USER命令
private string USER(string user)
{
return ExecuteCommand("USER " + user) + "/r/n";
}
//PASS命令
private string PASS(string password)
{
return ExecuteCommand("PASS " + password) + "/r/n";
}
//LIST命令
private string LIST()
{
return ExecuteCommand("LIST") + "/r/n";
}
//UIDL命令
private string UIDL()
{
return ExecuteCommand("UIDL") + "/r/n";
}
//NOOP命令
private string NOOP()
{
return ExecuteCommand("NOOP") + "/r/n";
}
//STAT命令
private string STAT()
{
return ExecuteCommand("STAT") + "/r/n";
}
//RETR命令
private string RETR(int number)
{
return ExecuteCommand("RETR " + number.ToString()) + "/r/n";
}
//DELE命令
private string DELE(int number)
{
return ExecuteCommand("DELE " + number.ToString()) + "/r/n";
}
//QUIT命令
private void Quit()
{
WriteToNetStream(ref mnetStream,"QUIT");
}
/// <summary>
/// 收取郵件
/// </summary>
/// <param name="user">用戶名</param>
/// <param name="password">口令</param>
/// <returns>
/// 類型:字符串數組
/// 內容:解碼前的郵件內容
/// </returns>
private string[] ReceiveMail(string user,string password)
{
int iMailNumber = 0; //郵件數
if(USER(user).Equals("Error"))
throw new Pop3Exception("用戶名不正確!");
if(PASS(password).Equals("Error"))
throw new Pop3Exception("用戶口令不正確!");
if(STAT().Equals("Error"))
throw new Pop3Exception("准備接收郵件時發生錯誤!");
if(LIST().Equals("Error"))
throw new Pop3Exception("得到郵件列表時發生錯誤!");
try
{
iMailNumber = GetMailNumber(mstrStatMessage);
//沒有新郵件
if(iMailNumber == 0)
return null;
else
{
string[] strMailContent = new string[iMailNumber];
for(int i = 1 ; i <= iMailNumber ; i++)
{
//讀取郵件內容
strMailContent[i - 1] = GetDecodeMailContent(RETR(i));
}
return strMailContent;
}
}
catch(Pop3Exception exc)
{
throw new Pop3Exception(exc.ToString());
}
}
#endregion
/// <summary>
/// 收取郵件
/// </summary>
/// <param name="user">用戶名</param>
/// <param name="password">口令</param>
/// <returns>
/// 類型:字符串數組
/// 內容:解碼前的郵件內容
/// </returns>
///<remarks>收取郵箱中的未讀郵件</remarks>
public string[] Receive(string user,string password)
{
try
{
return ReceiveMail(user,password);
}
catch(Pop3Exception exc)
{
throw new Pop3Exception(exc.ToString());
}
}
/// <summary>
/// 斷開所有與服務器的會話
/// </summary>
/// <remarks>斷開所有與服務器的會話</remarks>
public void DisConnect()
{
try
{
Quit();
if(m_stmReader != null)
m_stmReader.Close();
if(mnetStream != null)
mnetStream.Close();
if(mtcpClient != null)
mtcpClient.Close();
}
catch(SocketException exc)
{
throw new Pop3Exception(exc.ToString());
}
}
/// <summary>
/// 刪除郵件
/// </summary>
/// <param name="number">郵件號</param>
public void DeleteMail(int number)
{
//刪除郵件
int iMailNumber = number + 1;
if(DELE(iMailNumber).Equals("Error"))
throw new Pop3Exception("刪除第" + iMailNumber.ToString() + "時出現錯誤!");
}
}