Click here to Skip to main content
15,886,578 members
Articles / Programming Languages / C#

How to Create a Spam Filter or Automatic Category Sort Algorithm with Your Mail Application

Rate me:
Please Sign up or sign in to vote.
5.00/5 (9 votes)
29 Jul 2012MIT3 min read 40K   1.2K   19  
This article describes automatic category filters in mail applications.
In this article, you will learn how to create a spam filter on your mail application. You will also see how to filter your mail based on whether the mail tells about a particular topic or not.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.IO;
using System.Collections.Generic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using G = System.Collections.Generic;
using HigLabo.Net.Mail;
using HigLabo.Net.Internal;
using HigLabo.Net.Pop3;

namespace HigLabo.Net.Imap
{
    /// Represent and probide functionality about IMAP command.
    /// <summary>
    /// Represent and probide functionality about IMAP command.
    /// </summary>
    public class ImapClient : SocketClient, IDisposable
    {
        /// <summary>
        /// 
        /// </summary>
        public static readonly Int32 DefaultTagNo = 1;
        /// <summary>
        /// 
        /// </summary>
        public class RegexList
        {
            /// <summary>
            /// 
            /// </summary>
            public static readonly Regex SelectFolderResultFlagsLine = new Regex(@"^\* FLAGS \((?<Flags>[^)]*)\)\r\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
            /// <summary>
            /// 
            /// </summary>
            public static readonly Regex SelectFolderResult = new Regex(@"^\* (?<exst>\d+) EXISTS\r\n\* (?<rcnt>\d+) RECENT\r\n", RegexOptions.Multiline | RegexOptions.IgnoreCase);
            /// <summary>
            /// 
            /// </summary>
            public static readonly Regex GetListFolderResult = new Regex("^\\* LIST \\(((?<opt>\\\\\\w+)\\s?)+\\) \".\" \"(?<name>.*?)\"", RegexOptions.Multiline | RegexOptions.IgnoreCase);
            /// <summary>
            /// 
            /// </summary>
            public static readonly Regex GetLsubFolderResult = new Regex("^\\* LSUB \\(((?<opt>\\\\\\w+)\\s?)+\\) \".\" \"(?<name>.*?)\"", RegexOptions.Multiline | RegexOptions.IgnoreCase);
            /// <summary>
            /// 
            /// </summary>
            public static readonly Regex GetRlsubFolderResult = new Regex("^\\* LSUB \\(\\) \".\" (?<name>.*)", RegexOptions.Multiline | RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// 
        /// </summary>
        public static readonly Int32 DefaultPort = 143;
        private ImapConnectionState _State = ImapConnectionState.Disconnected;
        /// <summary>
        /// Get connection state.
        /// </summary>
        public ImapConnectionState State
        {
            get
            {
                if (this.Socket == null ||
                    this.Socket.Connected == false)
                {
                    this._State = ImapConnectionState.Disconnected;
                }
                return this._State;
            }
        }
        /// <summary>
        /// Get selected folder
        /// </summary>
        public ImapFolder CurrentFolder { get; private set; }
        /// <summary>
        /// Get connection is ready.
        /// </summary>
        public Boolean Available
        {
            get { return this._State != ImapConnectionState.Disconnected; }
        }
        /// <summary>
        /// 
        /// </summary>
        public Int32 TagNo { get; set; }
        private String Tag
        {
            get { return "tag" + this.TagNo; }
        }
        /// <summary>
        /// 
        /// </summary>
        public ImapClient(String serverName)
            : base(serverName, DefaultPort)
        {
            this.TagNo = ImapClient.DefaultTagNo;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="serverName"></param>
        /// <param name="port"></param>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        public ImapClient(String serverName, Int32 port, String userName, String password)
            : base(serverName, port)
        {
            this.UserName = userName;
            this.Password = password;
            this.TagNo = ImapClient.DefaultTagNo;
        }
        /// <summary>
        /// Open connection to a server.
        /// </summary>
        public ImapConnectionState Open()
        {
            if (this.Connect() == true)
            {
                this._State = ImapConnectionState.Connected;
            }
            else
            {
                this._State = ImapConnectionState.Disconnected;
            }
            return this._State;
        }
        /// サーバーへの接続が開かれていない場合、サーバーへの接続を開きます。
        /// <summary>
        /// Ensure connection is opened.
        /// サーバーへの接続が開かれていない場合、サーバーへの接続を開きます。
        /// </summary>
        public ImapConnectionState EnsureOpen()
        {
            if ((this.Socket != null) &&
                this.Socket.Connected)
            { return this._State; }

            return this.Open();
        }
        private void ValidateState(ImapConnectionState state)
        {
            this.ValidateState(state, false);
        }
        private void ValidateState(ImapConnectionState state, Boolean folderSelected)
        {
            if (this._State != state)
            {
                switch (state)
                {
                    case ImapConnectionState.Disconnected: throw new MailClientException("You can execute this command only when State is Disconnected");
                    case ImapConnectionState.Connected: throw new MailClientException("You can execute this command only when State is Connected");
                    case ImapConnectionState.Authenticated: throw new MailClientException("You can execute this command only when State is Authenticated");
                    default: throw new MailClientException();
                }
            }
            if (folderSelected == true && this.CurrentFolder == null)
            {
                throw new MailClientException("You must select folder before executing this command."
                  + "You can select folder by calling SelectFolder,ExecuteSelect,ExecuteExamine method of this object.");
            }
        }
        private String GetResponse()
        {
            MemoryStream ms = new MemoryStream();
            this.GetResponse(ms);
            return this.ResponseEncoding.GetString(ms.ToArray());
        }
        private void GetResponse(Stream stream)
        {
            Byte[] bb = this.GetResponseBytes(new ImapDataReceiveContext(this.Tag, this.ResponseEncoding));
            this.ReadText(stream, bb);
            this.Commnicating = false;
        }
        private void ReadText(Stream stream, Byte[] bytes)
        {
            String CurrentLine = "";
            Byte[] bb = null;
            StringReader sr = new StringReader(this.ResponseEncoding.GetString(bytes));

            while (true)
            {
                CurrentLine = sr.ReadLine();
                if (CurrentLine == null) { break; }
                bb = ResponseEncoding.GetBytes(CurrentLine + MailParser.NewLine);
                stream.Write(bb, 0, bb.Length);
            }
        }
        /// <summary>
        /// Log in to IMAP server.
        /// </summary>
        /// <returns></returns>
        public Boolean Authenticate()
        {
            if (this._State == ImapConnectionState.Authenticated) { return true; }
            var rs = this.ExecuteLogin();
            return this.State == ImapConnectionState.Authenticated;
        }
        private String Execute(String command)
        {
            this.Send(command);
            this.Commnicating = true;
            return this.GetResponse();
        }
        /// <summary>
        /// Send capability command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public CapabilityResult ExecuteCapability()
        {
            String s = this.Execute(this.Tag + " CAPABILITY");
            return new CapabilityResult(this.Tag, s);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteLogin()
        {
            if (this.EnsureOpen() == ImapConnectionState.Disconnected) { throw new MailClientException(); }

            String commandText = String.Format(this.Tag + " LOGIN {0} {1}", this.UserName, this.Password);
            String s = this.Execute(commandText);
            ImapCommandResult rs = new ImapCommandResult(this.Tag, s);
            if (rs.Status == ImapCommandResultStatus.Ok)
            {
                this._State = ImapConnectionState.Authenticated;
            }
            else
            {
                this._State = ImapConnectionState.Connected;
            }
            return rs;
        }
        /// <summary>
        /// Send Logout command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteLogout()
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " Logout");
            var rs = new ImapCommandResult(this.Tag, s);
            if (rs.Status == ImapCommandResultStatus.Ok)
            {
                this._State = ImapConnectionState.Connected;
            }
            return rs;
        }
        /// <summary>
        /// Send select command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public SelectResult ExecuteSelect(String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String commandText = String.Format(this.Tag + " Select {0}", NamingConversion.EncodeString(folderName));
            String s = this.Execute(commandText);
            var rs = this.GetSelectResult(folderName, s);
            this.CurrentFolder = new ImapFolder(rs);
            return rs;
        }
        /// <summary>
        /// Send examine command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public SelectResult ExecuteExamine(String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String commandText = String.Format(this.Tag + " Examine {0}", NamingConversion.EncodeString(folderName));
            String s = this.Execute(commandText);
            var rs = this.GetSelectResult(folderName, s);
            this.CurrentFolder = new ImapFolder(rs);
            return rs;
        }
        private SelectResult GetSelectResult(String folderName, String text)
        {
            var rs = new ImapCommandResult(this.Tag, text);
            if (rs.Status == ImapCommandResultStatus.Ok)
            {
                Int32 exists = 0;
                Int32 recent = 0;
                List<String> l = new List<string>();
                Match m = null;
                m = RegexList.SelectFolderResult.Match(rs.Text);
                if (m.Success)
                {
                    Int32.TryParse(m.Groups["exst"].Value, out exists);
                    Int32.TryParse(m.Groups["rcnt"].Value, out recent);
                }
                m = RegexList.SelectFolderResultFlagsLine.Match(rs.Text);
                if (m.Success == true)
                {
                    String flags = m.Groups["Flags"].Value;
                    foreach (var el in flags.Split(' '))
                    {
                        if (el.StartsWith("\\") == true)
                        {
                            l.Add(el.Substring(1, el.Length - 1));
                        }
                    }
                }
                return new SelectResult(folderName, exists, recent, l.ToArray());
            }
            throw new MailClientException();
        }
        /// <summary>
        /// Send create folder command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteCreate(String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String commandText = String.Format(this.Tag + " Create {0}", NamingConversion.EncodeString(folderName));
            String s = this.Execute(commandText);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send delete folder command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteDelete(String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String commandText = String.Format(this.Tag + " Delete {0}", NamingConversion.EncodeString(folderName));
            String s = this.Execute(commandText);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send close command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteClose()
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " Close");
            this.CurrentFolder = null;
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send list command to IMAP server.
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="recursive"></param>
        /// <returns></returns>
        public ListResult ExecuteList(String folderName, Boolean recursive)
        {
            this.ValidateState(ImapConnectionState.Authenticated);

            List<ListLineResult> l = new List<ListLineResult>();
            String name = "";
            Boolean noSelect = false;
            Boolean hasChildren = false;
            String rc = "%";
            if (recursive == true)
            {
                rc = "*";
            }
            String s = this.Execute(String.Format(this.Tag + " LIST \"{0}\" \"{1}\"", folderName, rc));
            foreach (Match m in RegexList.GetListFolderResult.Matches(s))
            {
                name = NamingConversion.DecodeString(m.Groups["name"].Value);
                foreach (Capture c in m.Groups["opt"].Captures)
                {
                    if (c.Value.ToString() == "\\Noselect")
                    {
                        noSelect = true;
                    }
                    else if (c.Value.ToString() == "\\HasNoChildren")
                    {
                        hasChildren = false;
                    }
                    else if (c.Value.ToString() == "\\HasChildren")
                    {
                        hasChildren = true;
                    }
                }
                l.Add(new ListLineResult(name, noSelect, hasChildren));
            }
            return new ListResult(l);
        }
        /// <summary>
        /// Send subscribe command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteSubscribe(String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " subscribe " + folderName);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send unsubscribe command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteUnsubscribe(String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " Unsubscribe " + folderName);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send list command to IMAP server.
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="recursive"></param>
        /// <returns></returns>
        public ListResult ExecuteLsub(String folderName, Boolean recursive)
        {
            this.ValidateState(ImapConnectionState.Authenticated);

            List<ListLineResult> l = new List<ListLineResult>();
            String name = "";
            Boolean noSelect = false;
            Boolean hasChildren = false;
            String rc = "%";
            if (recursive == true)
            {
                rc = "*";
            }
            String s = this.Execute(String.Format(this.Tag + " Lsub \"{0}\" \"{1}\"", folderName, rc));
            foreach (Match m in RegexList.GetLsubFolderResult.Matches(s))
            {
                name = NamingConversion.DecodeString(m.Groups["name"].Value);
                foreach (Capture c in m.Groups["opt"].Captures)
                {
                    if (c.Value.ToString() == "\\Noselect")
                    {
                        noSelect = true;
                    }
                    else if (c.Value.ToString() == "\\HasNoChildren")
                    {
                        hasChildren = false;
                    }
                    else if (c.Value.ToString() == "\\HasChildren")
                    {
                        hasChildren = true;
                    }
                }
                l.Add(new ListLineResult(name, noSelect, hasChildren));
            }
            return new ListResult(l);
        }
        /// <summary>
        /// Send Fetch command to IMAP server.
        /// </summary>
        /// <param name="mailIndex"></param>
        /// <returns></returns>
        public MailMessage ExecuteFetch(Int64 mailIndex)
        {
            this.ValidateState(ImapConnectionState.Authenticated, true);
            String s = this.Execute(String.Format(this.Tag + " FETCH {0} (BODY[])", mailIndex));
            Regex messageRegex = new Regex(@"^\* \d+ FETCH \([^\r\n]*BODY\[\] \{\d+\}\r\n(?<msg>.*?)\)\r\n" + this.Tag + " OK"
                , RegexOptions.Multiline | RegexOptions.Singleline);
            Match m = messageRegex.Match(s);
            if (m.Success)
            {
                s = m.Groups["msg"].Value;
                return new MailMessage(s, mailIndex);
            }
            throw new MailClientException();
        }
        /// <summary>
        /// Send search command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public SearchResult ExecuteSearch(String searchText)
        {
            this.ValidateState(ImapConnectionState.Authenticated, true);
            String s = this.Execute(this.Tag + " SEARCH " + searchText);
            return new SearchResult(this.Tag, s);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailIndex"></param>
        /// <param name="command"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        public ImapCommandResult ExecuteStore(Int64 mailIndex, StoreItem command, String flags)
        {
            this.ValidateState(ImapConnectionState.Authenticated, true);
            StringBuilder sb = new StringBuilder(256);
            sb.Append(this.Tag);
            sb.Append(" STORE ");
            sb.Append(mailIndex);
            sb.Append(" ");
            if (command == StoreItem.FlagsReplace)
            {
                sb.Append("FLAGS ");
            }
            else if (command == StoreItem.FlagsReplaceSilent)
            {
                sb.Append("FLAGS.SILENT ");
            }
            else if (command == StoreItem.FlagsAdd)
            {
                sb.Append("+FLAGS ");
            }
            else if (command == StoreItem.FlagsAddSilent)
            {
                sb.Append("+FLAGS.SILENT ");
            }
            else if (command == StoreItem.FlagsRemove)
            {
                sb.Append("-FLAGS ");
            }
            else if (command == StoreItem.FlagsRemoveSilent)
            {
                sb.Append("-FLAGS.SILENT ");
            }
            else
            {
                throw new ArgumentException("command");
            }
            if (String.IsNullOrEmpty(flags))
            {
                throw new ArgumentException("flags");
            }
            sb.Append("(");
            sb.Append(flags);
            sb.Append(")");

            var s = this.Execute(sb.ToString());
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="mailData"></param>
        /// <returns></returns>
        public ImapCommandResult ExecuteAppend(String folderName, String mailData)
        {
            return this.ExecuteAppend(folderName, mailData, "", DateTimeOffset.Now);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="mailData"></param>
        /// <param name="flag"></param>
        /// <param name="datetime"></param>
        /// <returns></returns>
        public ImapCommandResult ExecuteAppend(String folderName, String mailData, String flag, DateTimeOffset datetime)
        {
            String commandText = String.Format(this.Tag + " APPEND \"{0}\" ({1}) \"{2}\" "
                , NamingConversion.EncodeString(folderName), flag, MailParser.DateTimeOffsetString(datetime));
            commandText += "{" + mailData.Length + "}";
            String s = this.Execute(commandText);
            var rs = new ImapCommandResult(this.Tag, s);
            if (rs.Status == ImapCommandResultStatus.Ok ||
                rs.Status == ImapCommandResultStatus.None)
            {
                var ss = this.Execute(mailData);
                return new ImapCommandResult(this.Tag, ss);
            }
            return rs;
        }
        /// <summary>
        /// Send rename folder command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteRename(String oldFolderName, String folderName)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String commandText = String.Format(this.Tag + " Rename {0} {1}", NamingConversion.EncodeString(oldFolderName), NamingConversion.EncodeString(folderName));
            String s = this.Execute(commandText);
            var rs = new ImapCommandResult(this.Tag, s);
            if (rs.Status == ImapCommandResultStatus.Ok ||
                rs.Status == ImapCommandResultStatus.None)
            {
                return rs;
            }
            return rs;
        }
        /// <summary>
        /// Send rlsub command to IMAP server.
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="recursive"></param>
        /// <returns></returns>
        public ListResult ExecuteRlsub(String folderName, Boolean recursive)
        {
            this.ValidateState(ImapConnectionState.Authenticated);

            List<ListLineResult> l = new List<ListLineResult>();
            String name = "";
            Boolean noSelect = false;
            Boolean hasChildren = false;
            String rc = "%";
            if (recursive == true)
            {
                rc = "*";
            }
            String s = this.Execute(String.Format(this.Tag + " RLSUB \"{0}\" \"{1}\"", folderName, rc));
            foreach (Match m in RegexList.GetRlsubFolderResult.Matches(s))
            {
                name = NamingConversion.DecodeString(m.Groups["name"].Value);
                foreach (Capture c in m.Groups["opt"].Captures)
                {
                    if (c.Value.ToString() == "\\Noselect")
                    {
                        noSelect = true;
                    }
                    else if (c.Value.ToString() == "\\HasNoChildren")
                    {
                        hasChildren = false;
                    }
                    else if (c.Value.ToString() == "\\HasChildren")
                    {
                        hasChildren = true;
                    }
                }
                l.Add(new ListLineResult(name, noSelect, hasChildren));
            }
            return new ListResult(l);

        }
        /// <summary>
        /// Send status command to IMAP server.
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="message"></param>
        /// <param name="recent"></param>
        /// <param name="uidnext"></param>
        /// <param name="uidvalidity"></param>
        /// <param name="unseen"></param>
        /// <returns></returns>
        public ImapCommandResult ExecuteStatus(String folderName, Boolean message, Boolean recent, Boolean uidnext, Boolean uidvalidity, Boolean unseen)
        {
            String s = null;
            this.ValidateState(ImapConnectionState.Authenticated);
            StringBuilder sb = new StringBuilder(256);
            sb.Append(this.Tag);
            sb.Append(" Status");
            sb.Append(" ");
            sb.Append(folderName);
            if (message || recent || uidnext || uidvalidity || unseen)
            {
                sb.Append(" ");
                sb.Append("(");
                if (message)
                {
                    sb.Append("messages");
                }

                if (recent)
                {
                    sb.Append(" recent");
                }

                if (uidnext)
                {
                    sb.Append(" uidnext");
                }

                if (uidvalidity)
                {
                    sb.Append(" uidvalidity");
                }

                if (unseen)
                {
                    sb.Append(" unseen");
                }

                sb.Append(")");
            }

            s = this.Execute(sb.ToString());
            var rs = new ImapCommandResult(this.Tag, s);
            if (rs.Status == ImapCommandResultStatus.Ok ||
                rs.Status == ImapCommandResultStatus.None)
            {
                return rs;
            }
            return rs;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteCheck()
        {
            this.ValidateState(ImapConnectionState.Authenticated, true);
            String s = this.Execute(this.Tag + " Check");
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send copy command to IMAP server.
        /// </summary>
        /// <param name="mailindexstart"></param>
        /// <param name="mailindexend"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public ImapCommandResult ExecuteCopy(Int32 mailindexstart, Int32 mailindexend, String folderName)
        {
            String s = null;
            this.ValidateState(ImapConnectionState.Authenticated);
            StringBuilder sb = new StringBuilder(256);
            sb.Append(this.Tag);
            sb.Append(" Copy ");
            if (!Int32.Equals(mailindexstart, 0))
            {
                sb.Append(mailindexstart);
            }
            if (!Int32.Equals(mailindexend, 0) && !Int32.Equals(mailindexstart, 0))
            {
                sb.Append(":");
                sb.Append(mailindexend);
            }
            else if (!Int32.Equals(mailindexend, 0))
            {
                sb.Append(mailindexend);
            }
            sb.Append(" ");
            sb.Append(folderName);

            s = this.Execute(sb.ToString());
            var rs = new ImapCommandResult(this.Tag, s);
            if (rs.Status == ImapCommandResultStatus.Ok ||
                rs.Status == ImapCommandResultStatus.None)
            {
                return rs;
            }
            return rs;

        }
        /// <summary>
        /// Send UID command to IMAP server.
        /// <param name="command"></param>
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteUid(String command)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " UID " + command);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send NAMESPACE command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteNamespace()
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " NAMESPACE");
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ImapIdleCommand CreateImapIdleCommand()
        {
            return new ImapIdleCommand(this.Tag, this.ResponseEncoding);
        }
        /// <summary>
        /// Send IDLE command to IMAP server.
        /// You can receive message from server by register event handler to MessageReceived event of ImapIdleCommand object
        /// </summary>
        /// <returns></returns>
        public void ExecuteIdle(ImapIdleCommand command)
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            this.Send(this.Tag + " IDLE");
            var bb = command.GetByteArray();
            command.IAsyncResult = this.Stream.BeginRead(bb, 0, bb.Length, this.ExecuteIdleCallback, command);
            this._State = ImapConnectionState.Idle;
        }
        private void ExecuteIdleCallback(IAsyncResult result)
        {
            DataReceiveContext cx = null;

            try
            {
                cx = (DataReceiveContext)result.AsyncState;
                if (this.Socket == null)
                {
                    throw new SocketClientException("Connection is closed");
                }
                Int32 size = Stream.EndRead(result);
                if (cx.ReadBuffer(size) == true)
                {
                    var bb = cx.GetByteArray();
                    this.Stream.BeginRead(bb, 0, bb.Length, this.GetResponseCallback, cx);
                }
                else
                {
                    cx.Dispose();
                }
            }
            catch (Exception ex)
            {
                cx.Exception = ex;
                this.OnError(ex);
            }
            finally
            {
                if (cx.Exception != null)
                {
                    cx.Dispose();
                }
            }
        }
        /// <summary>
        /// Send done command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteDone(ImapIdleCommand command)
        {
            this.ValidateState(ImapConnectionState.Idle);
            if (command.IAsyncResult != null)
            {
                var x = this.Stream.EndRead(command.IAsyncResult);
            }
            String s = this.Execute("DONE");

            this._State = ImapConnectionState.Authenticated;

            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send GetQuota command to IMAP server.
        /// <param name="resourceName"></param>
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteGetQuota(String resourceName)
        {
            String s = this.Execute(this.Tag + " GetQuota " + resourceName);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send SETQUOTA command to IMAP server.
        /// <param name="resourceName"></param>
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteSetQuota(String resourceName)
        {
            String s = this.Execute(this.Tag + " SETQUOTA " + resourceName);
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send GETQUOTAROOT command to IMAP server.
        /// <param name="folderName"></param>
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteGetQuotaRoot(String folderName)
        {
            String s = this.Execute(this.Tag + " GETQUOTAROOT " + folderName);
            String commandText = String.Format(this.Tag + " GETQUOTAROOT {0}", NamingConversion.EncodeString(folderName));
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// Send noop command to IMAP server.
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteNoop()
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " NOOP");
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ImapCommandResult ExecuteExpunge()
        {
            this.ValidateState(ImapConnectionState.Authenticated);
            String s = this.Execute(this.Tag + " EXPUNGE");
            return new ImapCommandResult(this.Tag, s);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        public ImapFolder SelectFolder(String folderName)
        {
            var rs = this.ExecuteSelect(folderName);
            return new ImapFolder(rs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        public void UnselectFolder(String folderName)
        {
            this.ExecuteClose();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<ImapFolder> GetAllFolders()
        {
            return this.GetFolders("", true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="recursive"></param>
        /// <returns></returns>
        public List<ImapFolder> GetFolders(String folderName, Boolean recursive)
        {
            ValidateState(ImapConnectionState.Authenticated);
            List<ImapFolder> l = new List<ImapFolder>();
            var rs = this.ExecuteList(folderName, recursive);
            foreach (var el in rs.Lines)
            {
                l.Add(new ImapFolder(el));
            }
            return l;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailIndex"></param>
        /// <returns></returns>
        public MailMessage GetMessage(Int64 mailIndex)
        {
            return this.ExecuteFetch(mailIndex);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailIndex"></param>
        /// <returns></returns>
        public Boolean DeleteEMail(params Int64[] mailIndex)
        {
            this.ValidateState(ImapConnectionState.Authenticated, true);
            return this.DeleteEMail(this.CurrentFolder.Name, mailIndex);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="mailIndex"></param>
        /// <returns></returns>
        public Boolean DeleteEMail(String folderName, params Int64[] mailIndex)
        {
            if (this.EnsureOpen() == ImapConnectionState.Disconnected) { return false; }
            if (this.Authenticate() == false) { return false; }

            for (int i = 0; i < mailIndex.Length; i++)
            {
                var rs = this.ExecuteStore(mailIndex[i], StoreItem.FlagsAdd, @"\Deleted");
                if (rs.Status != ImapCommandResultStatus.Ok) { return false; }
            }
            this.ExecuteExpunge();
            this.ExecuteLogout();
            return true;
        }
        /// <summary>
        /// disconnect connection to IMAP server.
        /// </summary>
        public void Close()
        {
            this.Socket.Close();
            this.Socket = null;
            this._State = ImapConnectionState.Disconnected;
        }
        /// <summary>
        /// 
        /// </summary>
        ~ImapClient()
        {
            this.Dispose(false);
        }
    }
}

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 MIT License


Written By
CEO TinyBetter, Inc
Japan Japan
I'm a CEO of TinyBetter, Inc in Japan.

Comments and Discussions