public void DownloadFile(string remoteFilepath, string localFilepath)
        {
            if (ActiveMode)
            {
                var tcpSocket = PrepareActiveMode();

                var    buffer          = new byte[1024];
                Socket socket          = null;
                var    downloadingTask = Task.Run(() =>
                {
                    socket = tcpSocket.Accept();
                    using (var file = File.OpenWrite(localFilepath))
                    {
                        while (NetworkUtils.IsSocketConnected(socket))
                        {
                            var size = socket.Receive(buffer);
                            file.Write(buffer, 0, size);
                        }
                    }

                    socket.Disconnect(false);
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                });

                var(code, response) = _commandSender.Retr(remoteFilepath);
                if (code != 150)
                {
                    throw new Exception(response);
                }

                (code, response) = _commandSender.GetNextResponse();
                if (code != 226)
                {
                    throw new Exception(response);
                }

                downloadingTask.Wait();
            }
            else
            {
                var tcpSocket = PreparePassiveMode();

                // receive file on `tcpSocket`
                var buffer          = new byte[1024];
                var downloadingTask = Task.Run(() =>
                {
                    using (var file = File.OpenWrite(localFilepath))
                    {
                        while (NetworkUtils.IsSocketConnected(tcpSocket))
                        {
                            var size = tcpSocket.Receive(buffer);
                            file.Write(buffer, 0, size);
                        }
                    }

                    tcpSocket.Disconnect(false);
                    tcpSocket.Shutdown(SocketShutdown.Both);
                    tcpSocket.Close();
                });

                var(code, response) = _commandSender.Retr(remoteFilepath);
                if (code != 150)
                {
                    throw new Exception(response);
                }

                (code, response) = _commandSender.GetNextResponse();
                if (code != 226)
                {
                    throw new Exception(response);
                }

                downloadingTask.Wait();
            }
        }
        public List <(bool IsDir, long Size, string LastModificationTime, string Name)> ListFiles(string filepath = null)
        {
            var fileList = "";

            if (ActiveMode)
            {
                var tcpSocket = PrepareActiveMode();

                var    buffer       = new byte[1024];
                Socket socket       = null;
                var    retrivalTask = Task.Run(() =>
                {
                    socket = tcpSocket.Accept();
                    while (NetworkUtils.IsSocketConnected(socket))
                    {
                        var size  = socket.Receive(buffer);
                        fileList += Encoding.ASCII.GetString(buffer, 0, size);
                    }

                    socket.Disconnect(false);
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                });

                var(code, response) = _commandSender.List(filepath);
                if (code != 150)
                {
                    throw new Exception(response);
                }

                (code, response) = _commandSender.GetNextResponse();
                if (code != 226)
                {
                    throw new Exception(response);
                }

                tcpSocket.Close();
                retrivalTask.Wait();
            }
            else
            {
                var tcpSocket = PreparePassiveMode();

                // receive list on `tcpSocket`
                var buffer = new byte[1024];

                var retrivalTask = Task.Run(() =>
                {
                    while (NetworkUtils.IsSocketConnected(tcpSocket))
                    {
                        var size  = tcpSocket.Receive(buffer);
                        fileList += Encoding.ASCII.GetString(buffer, 0, size);
                    }

                    tcpSocket.Disconnect(false);
                    tcpSocket.Shutdown(SocketShutdown.Both);
                    tcpSocket.Close();
                });

                var(code, response) = _commandSender.List(filepath);
                if (code != 150)
                {
                    throw new Exception(response);
                }

                (code, response) = _commandSender.GetNextResponse();
                if (code != 226)
                {
                    throw new Exception(response);
                }

                retrivalTask.Wait();
            }

            var slices = fileList.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            var ret    = new List <(bool IsDir, long Size, string LastModificationTime, string Name)>();

            foreach (var slice in slices)
            {
                var match = Regex.Match(slice.Trim(),
                                        @"^(.{10})\s+\d+\s+.*?\s+.*?\s+(\d+)\s+(.*?\s+.*?\s+.*?)\s+(.*)$");
                var isDir = match.Groups[1].Value.StartsWith("d");
                var size  = long.Parse(match.Groups[2].Value);
                var lastModificationTime = match.Groups[3].Value;
                var name = match.Groups[4].Value;
                ret.Add((isDir, size, lastModificationTime, name));
            }

            return(ret);
        }