コード例 #1
0
        private void HandleControl(object state)
        {
            try
            {
                LogUser.Address = Client.Client.RemoteEndPoint.ToString();
                LogUser.LogMsg($"220 Ready As I'll Ever Be");
                ControlWriter.WriteLine("220 Ready As I'll Ever Be");
                ControlWriter.Flush();

                string line = null;

                while (!string.IsNullOrEmpty(line = ControlReader.ReadLine()))
                {
                    LogUser.LogMsg($"Command: {line}");
                    string response = null;
                    bool   authTls  = false;

                    string[] command = line.Split(' ');
                    string   cmd     = command[0].ToUpperInvariant();
                    string   args    = command.Length > 1 ? line.Substring(command[0].Length + 1) : null;

                    if (response == null)
                    {
                        switch (cmd)
                        {
                        case "USER":
                            if (LoggedIn)
                            {
                                response = "230 User already logged in";
                                break;
                            }
                            response = Login(args);
                            break;

                        case "PASS":
                            response = Login(args);
                            break;

                        case "AUTH":
                            if (args == "TLS" || args == "SSL")
                            {
                                response = "234 Enable TLS/SSL Connection";
                                authTls  = true;
                                break;
                            }
                            response = $"502 Unknown Argument '{args}'";
                            break;

                        // File Commands
                        case "CDUP":
                            response = ChangeWD("..");
                            break;

                        case "CWD":
                            response = ChangeWD(args);
                            break;

                        case "PWD":
                            try
                            {
                                string cur = CurrentDir.Replace(Root, string.Empty).Replace('\\', '/');
                                response = cur.Length > 0 ? cur : "257 \"/\" is current directory";
                            }
                            catch
                            {
                                response = "550 PWD Failed Sucessfully";
                            }
                            break;

                        case "TYPE":
                            string[] splitArgs = args.Split(' ');
                            response = Type(splitArgs[0], splitArgs.Length > 1 ? splitArgs[1] : null);
                            break;

                        case "PASV":
                            response = Passive();
                            break;

                        case "PORT":
                            response = Port(args);
                            break;

                        case "LIST":
                            response = List(args ?? CurrentDir);
                            break;

                        case "RETR":
                            response = Retrieve(args);
                            break;

                        case "STOR":
                            response = Store(args);
                            break;

                        case "RNFR":
                            renameFrom = args;
                            response   = "350 Requested file action pending further information";
                            break;

                        case "RNTO":
                            response = Rename(renameFrom, args);
                            break;

                        case "PBSZ":
                            response = $"200 PBSZ={args}";
                            break;

                        case "PROT":
                            response = $"200 Protection level set to {args}";
                            Protocol = (args == "P") ? Protocol.P : Protocol.C;
                            break;

                        case "MLSD":
                            response = MLSD(args);
                            break;

                        case "NLSD":
                            response = NLST(args);
                            break;

                        case "SIZE":
                            args = Helpers.NormalizeFilename(args, Root, CurrentDir);
                            if (!Helpers.IsValidPath(args, Root))
                            {
                                response = "550 File Not Found";
                                break;
                            }
                            response = (File.Exists(args)) ? $"213 {new FileInfo(args).Length}" : "550 File Not Found";
                            break;

                        case "MDTM":
                            args = Helpers.NormalizeFilename(args, Root, CurrentDir);
                            if (!Helpers.IsValidPath(args, Root))
                            {
                                response = "550 File Not Found";
                                break;
                            }
                            response = (File.Exists(args)) ? $"213 {new FileInfo(args).LastWriteTime:yyyyMMddHHmmss.fff}" : "550 File Not Found";
                            break;

                        case "QUIT":
                            response = "221 Goodbye";
                            break;

                        case "DELE":
                            response = Delete(args);
                            break;

                        case "RMD":
                            response = RemoveDir(args);
                            break;

                        case "MKD":
                            response = CreateDir(args);
                            break;

                        case "SYST":
                            response = "215 UNIX Type: L8";
                            break;

                        default:
                            response = $"502 Command '{line}' Not Implemented";
                            break;
                        }

                        try
                        {
                            LogUser.LogMsg($"Response: {response}");
                            ControlWriter.WriteLine(response);
                            ControlWriter.Flush();
                        }
                        catch { }

                        if (response.StartsWith("221"))
                        {
                            if (SslControlStream != null)
                            {
                                SslControlStream.Dispose();
                            }
                            Client.Close();
                            break;
                        }

                        if (authTls)
                        {
                            SslControlStream = new FixedSslStream(ControlStream);
                            SslControlStream.AuthenticateAsServer(X509, false, SslProtocols.Default, false);
                            ControlWriter = new StreamWriter(SslControlStream);
                            ControlReader = new StreamReader(SslControlStream);
                        }
                    }
                }
                Logger.UnregisterUser(LogUser);
            }
            catch (Exception e)
            {
                Logger.Log($"Client {Client.Client.RemoteEndPoint} disconnected due to an error ({e.Message})");
                Client.Close();
                Logger.UnregisterUser(LogUser);
            }
        }