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); } }