Exemplo n.º 1
0
        /// <summary>
        /// Process an FTP command.
        /// </summary>
        private void ProcessCommand(string verb, string arguments)
        {
            switch (verb)
            {
            case "SYST":
            {
                Respond(215, "UNIX emulated by mooftpserv");
                break;
            }

            case "QUIT":
            {
                Respond(221, "Bye.");
                // first flush, then close
                controlSocket.Shutdown(SocketShutdown.Both);
                controlSocket.Close();
                break;
            }

            case "USER":
            {
                Respond(230, "You are already logged in.");
                break;
            }

            case "PASS":
            {
                Respond(230, "You are already logged in.");
                break;
            }

            case "FEAT":
            {
                Respond(211, "Features:\r\n " + String.Join("\r\n ", FEATURES), true);
                Respond(211, "Features done.");
                break;
            }

            case "OPTS":
            {
                // Windows Explorer uses lowercase args
                if (arguments != null && arguments.ToUpper() == "UTF8 ON")
                {
                    Respond(200, "Always in UTF8 mode.");
                }
                else
                {
                    Respond(504, "Unknown option.");
                }
                break;
            }

            case "TYPE":
            {
                if (arguments == "A" || arguments == "A N")
                {
                    transferDataType = DataType.ASCII;
                    Respond(200, "Switching to ASCII mode.");
                }
                else if (arguments == "I")
                {
                    transferDataType = DataType.IMAGE;
                    Respond(200, "Switching to BINARY mode.");
                }
                else
                {
                    Respond(500, "Unknown TYPE arguments.");
                }
                break;
            }

            case "PORT":
            {
                IPEndPoint port = ParseAddress(arguments);
                if (port == null)
                {
                    Respond(500, "Invalid host-port format.");
                    break;
                }

                if (!authHandler.AllowActiveDataConnection(port))
                {
                    Respond(500, "PORT arguments refused.");
                    break;
                }

                dataPort = port;
                CreateDataSocket(false);
                Respond(200, GetRandomText(OK_TEXT));
                break;
            }

            case "PASV":
            {
                dataPort = null;

                try {
                    CreateDataSocket(true);
                } catch (Exception ex) {
                    Respond(500, ex);
                    break;
                }

                string port = FormatAddress((IPEndPoint)dataSocket.LocalEndPoint);
                Respond(227, String.Format("Switched to passive mode ({0})", port));
                break;
            }

            case "XPWD":
            case "PWD":
            {
                ResultOrError <string> ret = fsHandler.GetCurrentDirectory();
                if (ret.HasError)
                {
                    Respond(500, ret.Error);
                }
                else
                {
                    Respond(257, EscapePath(ret.Result));
                }
                break;
            }

            case "XCWD":
            case "CWD":
            {
                ResultOrError <string> ret = fsHandler.ChangeDirectory(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(200, GetRandomText(OK_TEXT));
                }
                break;
            }

            case "XCUP":
            case "CDUP":
            {
                ResultOrError <string> ret = fsHandler.ChangeDirectory("..");
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(200, GetRandomText(OK_TEXT));
                }
                break;
            }

            case "XMKD":
            case "MKD":
            {
                ResultOrError <string> ret = fsHandler.CreateDirectory(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(257, EscapePath(ret.Result));
                }
                break;
            }

            case "XRMD":
            case "RMD":
            {
                ResultOrError <bool> ret = fsHandler.RemoveDirectory(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(250, GetRandomText(OK_TEXT));
                }
                break;
            }

            case "RETR":
            {
                ResultOrError <Stream> ret = fsHandler.ReadFile(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                    break;
                }

                SendData(ret.Result);
                break;
            }

            case "STOR":
            {
                ResultOrError <Stream> ret = fsHandler.WriteFile(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                    break;
                }
                ReceiveData(ret.Result);
                var ret2 = fsHandler.WriteFileFinalize(arguments, ret.Result);
                if (ret2.HasError)
                {
                    Respond(550, ret.Error);
                    break;
                }
                break;
            }

            case "DELE":
            {
                ResultOrError <bool> ret = fsHandler.RemoveFile(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(250, GetRandomText(OK_TEXT));
                }
                break;
            }

            case "RNFR":
            {
                if (arguments == null || arguments.Trim() == "")
                {
                    Respond(500, "Empty path is invalid.");
                    break;
                }

                renameFromPath = arguments;
                Respond(350, "Waiting for target path.");
                break;
            }

            case "RNTO":
            {
                if (renameFromPath == null)
                {
                    Respond(503, "Use RNFR before RNTO.");
                    break;
                }

                ResultOrError <bool> ret = fsHandler.RenameFile(renameFromPath, arguments);
                renameFromPath = null;
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(250, GetRandomText(OK_TEXT));
                }
                break;
            }

            case "MDTM":
            {
                ResultOrError <DateTime> ret = fsHandler.GetLastModifiedTimeUtc(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(213, FormatTime(EnsureUnixTime(ret.Result)));
                }
                break;
            }

            case "SIZE":
            {
                ResultOrError <long> ret = fsHandler.GetFileSize(arguments);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(213, ret.Result.ToString());
                }
                break;
            }

            case "LIST":
            {
                // apparently browsers like to pass arguments to LIST
                // assuming they are passed through to the UNIX ls command
                arguments = RemoveLsArgs(arguments);

                ResultOrError <FileSystemEntry[]> ret = fsHandler.ListEntries(arguments);
                if (ret.HasError)
                {
                    Respond(500, ret.Error);
                    break;
                }

                SendData(MakeStream(FormatDirList(ret.Result)));
                break;
            }

            case "STAT":
            {
                if (arguments == null || arguments.Trim() == "")
                {
                    Respond(504, "Not implemented for these arguments.");
                    break;
                }

                arguments = RemoveLsArgs(arguments);

                ResultOrError <FileSystemEntry[]> ret = fsHandler.ListEntries(arguments);
                if (ret.HasError)
                {
                    Respond(500, ret.Error);
                    break;
                }

                Respond(213, "Status:\r\n" + FormatDirList(ret.Result), true);
                Respond(213, "Status done.");
                break;
            }

            case "NLST":
            {
                // remove common arguments, we do not support any of them
                arguments = RemoveLsArgs(arguments);

                ResultOrError <FileSystemEntry[]> ret = fsHandler.ListEntries(arguments);
                if (ret.HasError)
                {
                    Respond(500, ret.Error);
                    break;
                }

                SendData(MakeStream(FormatNLST(ret.Result)));
                break;
            }

            case "NOOP":
            {
                Respond(200, GetRandomText(OK_TEXT));
                break;
            }

            case "SITE":
            {
                string[] tokens  = arguments.Split(' ');
                var      newverb = tokens[0].ToUpper(); // commands are case insensitive
                var      newargs = (tokens.Length > 1 ? String.Join(" ", tokens, 1, tokens.Length - 1) : null);
                ProcessCommand(newverb, newargs);
                break;
            }

            case "CHMOD":
            {
                string[]             tokens = arguments.Split(' ');
                var                  mode   = tokens[0].ToUpper(); // commands are case insensitive
                var                  file   = (tokens.Length > 1 ? String.Join(" ", tokens, 1, tokens.Length - 1) : "");
                ResultOrError <bool> ret    = fsHandler.ChmodFile(mode, file);
                if (ret.HasError)
                {
                    Respond(550, ret.Error);
                }
                else
                {
                    Respond(250, GetRandomText(OK_TEXT));
                }
                break;
            }

            default:
            {
                Respond(500, "Unknown command.");
                break;
            }
            }
        }