using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Net.Configuration;
using System.Configuration;

namespace Winson.Framework.Utility.Mail
{
    #region 邮件接收类

    /// <summary>
    /// 邮件接收类
    /// </summary>
    public class POP3
    {
        #region Fields

        string POPServer;
        string mPOPUserName;
        string mPOPPass;
        int mPOPPort;
        NetworkStream ns;
        StreamReader sr;

        #endregion

        #region Constructors

        /// <summary>
        /// POP3
        /// </summary>
        /// <param name="server">POP3服务器名称</param>
        /// <param name="userName">用户名</param>
        /// <param name="password">用户密码</param>
        public POP3(string server, string userName, string password)
            : this(server, 110, userName, password)
        {
        }

        /// <summary>
        /// POP3
        /// </summary>
        /// <param name="server">POP3服务器名称</param>
        /// <param name="port">端口号</param>
        /// <param name="userName">用户名</param>
        /// <param name="password">用户密码</param>
        public POP3(string server, int port, string userName, string password)
        {
            POPServer = server;
            mPOPUserName = userName;
            mPOPPass = password;
            mPOPPort = port;
        }

        #endregion

        #region Methods

        #region Public

        /// <summary>
        /// 获得新邮件数量
        /// </summary>
        /// <returns>新邮件数量</returns>
        public int GetNumberOfNewMessages()
        {
            byte[] outbytes;
            string input;

            try
            {
                Connect();

                input = "stat" + "\r\n";
                outbytes = System.Text.Encoding.ASCII.GetBytes(input.ToCharArray());
                ns.Write(outbytes, 0, outbytes.Length);
                string resp = sr.ReadLine();
                string[] tokens = resp.Split(new Char[] { ' ' });

                Disconnect();

                return Convert.ToInt32(tokens[1]);
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>
        /// 获取新邮件内容
        /// </summary>
        /// <param name="subj">邮件主题</param>
        /// <returns>新邮件内容</returns>
        public List<MailMessage> GetNewMessages(string subj)
        {

            int newcount;
            List<MailMessage> newmsgs = new List<MailMessage>();

            try
            {
                newcount = GetNumberOfNewMessages();
                Connect();

                for (int n = 1; n < newcount + 1; n++)
                {
                    List<string> msglines = GetRawMessage(n);
                    string msgsubj = GetMessageSubject(msglines);
                    if (msgsubj.CompareTo(subj) == 0)
                    {
                        MailMessage msg = new MailMessage();
                        msg.Subject = msgsubj;
                        msg.From = new MailAddress(GetMessageFrom(msglines));
                        msg.Body = GetMessageBody(msglines);
                        newmsgs.Add(msg);
                        DeleteMessage(n);
                    }
                }

                Disconnect();
                return newmsgs;
            }
            catch (Exception e)
            {
                return newmsgs;
            }
        }

        /// <summary>
        /// 获取新邮件内容
        /// </summary>
        /// <param name="nIndex">新邮件索引</param>
        /// <returns>新邮件内容</returns>
        public MailMessage GetNewMessages(int nIndex)
        {
            int newcount;
            MailMessage msg = new MailMessage();

            try
            {
                newcount = GetNumberOfNewMessages();
                Connect();
                int n = nIndex + 1;

                if (n < newcount + 1)
                {
                    List<string> msglines = GetRawMessage(n);
                    string msgsubj = GetMessageSubject(msglines);


                    msg.Subject = msgsubj;
                    msg.From = new MailAddress(GetMessageFrom(msglines));
                    msg.Body = GetMessageBody(msglines);
                }

                Disconnect();
                return msg;
            }
            catch
            {
                return null;
            }
        }

        #endregion

        #region Private

        private bool Connect()
        {
            TcpClient sender = new TcpClient(POPServer, mPOPPort);
            byte[] outbytes;
            string input;

            try
            {
                ns = sender.GetStream();
                sr = new StreamReader(ns);

                sr.ReadLine();
                input = "user " + mPOPUserName + "\r\n";
                outbytes = System.Text.Encoding.ASCII.GetBytes(input.ToCharArray());
                ns.Write(outbytes, 0, outbytes.Length);
                sr.ReadLine();

                input = "pass " + mPOPPass + "\r\n";
                outbytes = System.Text.Encoding.ASCII.GetBytes(input.ToCharArray());
                ns.Write(outbytes, 0, outbytes.Length);
                sr.ReadLine();
                return true;

            }
            catch
            {
                return false;
            }
        }

        private void Disconnect()
        {
            string input = "quit" + "\r\n";
            Byte[] outbytes = System.Text.Encoding.ASCII.GetBytes(input.ToCharArray());
            ns.Write(outbytes, 0, outbytes.Length);
            ns.Close();
        }

        private List<string> GetRawMessage(int messagenumber)
        {
            Byte[] outbytes;
            string input;
            string line = "";

            input = "retr " + messagenumber.ToString() + "\r\n";
            outbytes = System.Text.Encoding.ASCII.GetBytes(input.ToCharArray());
            ns.Write(outbytes, 0, outbytes.Length);

            List<string> msglines = new List<string>();
            do
            {
                line = sr.ReadLine();
                msglines.Add(line);
            } while (line != ".");
            msglines.RemoveAt(msglines.Count - 1);

            return msglines;
        }

        private string GetMessageSubject(List<string> msglines)
        {
            string[] tokens;
            IEnumerator msgenum = msglines.GetEnumerator();
            while (msgenum.MoveNext())
            {
                string line = (string)msgenum.Current;
                if (line.StartsWith("Subject:"))
                {
                    tokens = line.Split(new Char[] { ' ' });
                    return tokens[1].Trim();
                }
            }
            return "None";
        }

        private string GetMessageFrom(List<string> msglines)
        {
            string[] tokens;
            IEnumerator msgenum = msglines.GetEnumerator();
            while (msgenum.MoveNext())
            {
                string line = (string)msgenum.Current;
                if (line.StartsWith("From:"))
                {
                    tokens = line.Split(new Char[] { '<' });
                    return tokens[1].Trim(new Char[] { '<', '>' });
                }
            }
            return "None";
        }

        private string GetMessageBody(List<string> msglines)
        {
            string body = "";
            string line = " ";
            IEnumerator msgenum = msglines.GetEnumerator();

            while (line.CompareTo("") != 0)
            {
                msgenum.MoveNext();
                line = (string)msgenum.Current;
            }

            while (msgenum.MoveNext())
            {
                body = body + (string)msgenum.Current + "\r\n";
            }
            return body;
        }

        private void DeleteMessage(int messagenumber)
        {
            Byte[] outbytes;
            string input;

            try
            {
                input = "dele " + messagenumber.ToString() + "\r\n";
                outbytes = System.Text.Encoding.ASCII.GetBytes(input.ToCharArray());
                ns.Write(outbytes, 0, outbytes.Length);
            }
            catch (Exception e)
            {
                return;
            }

        }

        #endregion

        #endregion
    }

    #endregion

    #region 邮件发送类

    public class SMTP
    {

        #region Fields

        private string _mailFrom;
        private string _displayName;
        private SmtpClient smtpMail;
        private string mSMTPServer;
        private int mSMTPPort;
        private string mSMTPUsername;
        private string mSMTPPassword;
        private bool mSMTPSSL;


        #endregion

        #region Properties

        public string MailFrom
        {
            get { return _mailFrom; }
            set { _mailFrom = value; }
        }

        public string DisplayName
        {
            get { return _displayName; }
            set { _displayName = value; }
        }
        public string SMTPServer
        {
            get { return mSMTPServer; }
            set { mSMTPServer = value; }
        }
        public int SMTPPort
        {
            get { return mSMTPPort; }
            set { mSMTPPort = value; }
        }
        public string SMTPUsername
        {
            get { return mSMTPUsername; }
            set { mSMTPUsername = value; }
        }
        public string SMTPPassword
        {
            get { return mSMTPPassword; }
            set { mSMTPPassword = value; }
        }
        public bool SMTPSSL
        {
            get { return mSMTPSSL; }
            set { mSMTPSSL = value; }
        }

        #endregion

        #region Constructors

        public SMTP()
        {
            // System.Configuration.Configuration config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/");
            //  MailSettingsSectionGroup mailSettings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");

            //string mailFrom = _mailFrom;
            //string smtpServer = mSMTPServer;
            //int smtpPort = mSMTPPort;
            //string smtpUsername = mSMTPUsername;
            //string password = mSMTPPassword;

            //smtpMail = new SmtpClient(smtpServer, smtpPort);
            //smtpMail.Credentials = new NetworkCredential(smtpUsername, password);

            //this._mailFrom = mailFrom;
            //this._displayName = smtpUsername;
        }

        public SMTP(string smtpServer, string userName, string password)
            : this(null, smtpServer, userName, password)
        {
        }

        /**/
        /// <summary>
        /// 邮件发送类
        /// </summary>
        /// <param name="mailFrom">发件人地址</param>
        /// <param name="smtpServer">SMTP 服务器</param>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        public SMTP(string mailFrom, string smtpServer, string userName, string password)
            : this(mailFrom, mailFrom, smtpServer, userName, password)
        {

        }

        /**/
        /// <summary>
        /// 邮件发送类
        /// </summary>
        /// <param name="mailFrom">发件人地址</param>
        /// <param name="displayName">显示的名称</param>
        /// <param name="smtpServer">SMTP 服务器</param>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        public SMTP(string mailFrom, string displayName, string smtpServer, string userName, string password)
            : this(mailFrom, displayName, smtpServer, 25, userName, password, false)
        {
        }

        public SMTP(string mailFrom, string displayName, string smtpServer, int smtpPort, string userName, string password, bool smtpSsl)
        {
            //this._mailFrom = mailFrom;
            //this._displayName = displayName;
            //smtpMail = new SmtpClient(smtpServer, smtpPort);
            //smtpMail.Credentials = new NetworkCredential(userName, password);
            //smtpMail.EnableSsl = smtpSsl;
        }


        #endregion

        #region Methods

        #region Public

        public Boolean Send(string mailTo, string mailSubject, string mailBody, MailPriority priority, bool isBodyHtml)
        {
            string[] mailTos = new string[] { mailTo };
            string[] attachments = null;
            System.Text.Encoding bodyEncoding = System.Text.Encoding.Default;
            return Send(mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        public Boolean Send(string mailTo, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            string[] mailTos = new string[] { mailTo };
            return Send(mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        public Boolean Send(string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            return Send(this._mailFrom, this._displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        /**/
        /// <summary>
        /// 同步发送邮件
        /// </summary>
        /// <returns></returns>
        public Boolean Send(string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            return SendMail(false, null, mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        public void SendAsync(object userState, string mailTo, string mailSubject, string mailBody, MailPriority priority, bool isBodyHtml)
        {
            string[] mailTos = new string[] { mailTo };
            string[] attachments = null;
            System.Text.Encoding bodyEncoding = System.Text.Encoding.Default;
            SendAsync(userState, mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        public void SendAsync(object userState, string mailTo, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            string[] mailTos = new string[] { mailTo };
            SendAsync(userState, this._mailFrom, this._displayName, mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        public void SendAsync(object userState, string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            SendMail(true, userState, mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }

        /**/
        /// <summary>
        /// 异步发送邮件
        /// </summary>
        /// <param name="userState">异步任务的唯一标识符</param>
        /// <returns></returns>
        public void SendAsync(object userState, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            SendMail(true, userState, null, null, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
        }


        /**/
        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="isAsync">是否异步发送邮件</param>
        /// <param name="userState">异步任务的唯一标识符，当 isAsync 为 True 时必须设置该属性， 当 isAsync 为 False 时可设置为 null</param>
        /// <returns></returns>
        private Boolean SendMail(bool isAsync, object userState, string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            bool mailSent = false;


            string smtpServer = mSMTPServer;
            int smtpPort = mSMTPPort;
            string smtpUsername = mSMTPUsername;
            string password = mSMTPPassword;

            smtpMail = new SmtpClient(smtpServer, smtpPort);
            smtpMail.Credentials = new NetworkCredential(smtpUsername, password);

            #region 设置属性值

            if (string.IsNullOrEmpty(mailFrom))
                mailFrom = this._mailFrom;

            if (string.IsNullOrEmpty(displayName))
                displayName = this._displayName;

            MailMessage Email = GetMailMessage(mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);

            smtpMail.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);

            #endregion

            try
            {
                if (!isAsync)
                {
                    smtpMail.Send(Email);
                    mailSent = true;
                }
                else
                {
                    userState = (userState == null) ? Guid.NewGuid() : userState;
                    smtpMail.SendAsync(Email, userState);
                }
            }
            catch (SmtpFailedRecipientsException ex)
            {
                // System.Windows.Forms.MessageBox.Show(ex.Message);
                mailSent = false;
            }
            catch (Exception ex)
            {
                // System.Windows.Forms.MessageBox.Show(ex.Message);

                mailSent = false;
            }


            return mailSent;
        }

        #endregion

        #region Private

        private MailMessage GetMailMessage(string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
        {
            // build the email message
            MailMessage emailMessage = new MailMessage();

            if (string.IsNullOrEmpty(mailFrom))
                mailFrom = this._mailFrom;

            if (string.IsNullOrEmpty(displayName))
                displayName = this._displayName;

            MailAddress mailFromObject = new MailAddress(mailFrom, displayName);

            emailMessage.From = mailFromObject;

            if (mailTos != null)
            {
                foreach (string mailto in mailTos)
                {
                    if (!string.IsNullOrEmpty(mailto))
                    {
                        emailMessage.To.Add(mailto);
                    }
                }
            }

            if (mailCcs != null)
            {
                foreach (string cc in mailCcs)
                {
                    if (!string.IsNullOrEmpty(cc))
                    {
                        emailMessage.CC.Add(cc);
                    }
                }
            }

            if (mailBccs != null)
            {
                foreach (string bcc in mailBccs)
                {
                    if (!string.IsNullOrEmpty(bcc))
                    {
                        emailMessage.Bcc.Add(bcc);
                    }
                }
            }

            if (attachments != null)
            {
                foreach (string file in attachments)
                {
                    if (!string.IsNullOrEmpty(file))
                    {
                        Attachment att = new Attachment(file);
                        emailMessage.Attachments.Add(att);
                    }
                }
            }

            emailMessage.Subject = mailSubject;
            emailMessage.Body = mailBody;
            emailMessage.Priority = priority;
            emailMessage.IsBodyHtml = isBodyHtml;
            emailMessage.BodyEncoding = bodyEncoding;

            return emailMessage;
        }

        private void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            bool mailSent = false;

            // Get the unique identifier for this asynchronous operation.
            String token = e.UserState.ToString();

            if (e.Cancelled)
            {
                //Console.WriteLine("[{0}] Send canceled.", token);
                mailSent = false;
            }
            if (e.Error != null)
            {
                //Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
                mailSent = false;
            }
            else
            {
                //Console.WriteLine("Message sent.");
                mailSent = false;
            }

            mailSent = true;
        }

        #endregion

        #endregion
    }

    #endregion
}
