/// <summary>
        /// Initializes a new instance of the <see cref="FtpServerFactory"/> class
        /// with the provided server options.
        /// </summary>
        /// <param name="serverOptions">FTP server options</param>
        public FtpServerFactory(FtpServerOptions serverOptions)
        {
            if (serverOptions == null)
            {
                throw new ArgumentNullException(nameof(serverOptions));
            }

            this.serverOptions = serverOptions;
            supportedCommands  = GetSupportedCommands(serverOptions);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpSessionState"/> class
        /// with the provided server address, control channel, server options and logger.
        /// </summary>
        /// <param name="serverAddress">Address of the server</param>
        /// <param name="publicServerAddress">
        /// External IP address of the server. This address will be used in passive mode
        /// </param>
        /// <param name="controlChannel">Control channel for the session</param>
        /// <param name="serverOptions">FTP server options</param>
        /// <param name="logger">Current logger instance</param>
        public FtpSessionState(
            IPAddress serverAddress,
            IPAddress publicServerAddress,
            IControlChannel controlChannel,
            FtpServerOptions serverOptions,
            ILogger logger)
        {
            if (serverAddress == null)
            {
                throw new ArgumentNullException(nameof(serverAddress));
            }

            if (publicServerAddress == null)
            {
                throw new ArgumentNullException(nameof(publicServerAddress));
            }

            if (controlChannel == null)
            {
                throw new ArgumentNullException(nameof(controlChannel));
            }

            if (serverOptions == null)
            {
                throw new ArgumentNullException(nameof(serverOptions));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            ServerAddress       = serverAddress;
            PublicServerAddress = publicServerAddress;
            ControlChannel      = controlChannel;
            LineFeed            = serverOptions.CommandEncoding.GetBytes(serverOptions.LineFeed);
            Logger = logger;

            ControlEncoding = serverOptions.CommandEncoding;
            PathEncoding    = Encoding.ASCII;

            TransferType = FileTransferType.ASCII;
        }
 /// <summary>
 /// Creates the list of all FTP commands supported by the server.
 /// </summary>
 /// <param name="serverOptions">FTP server options</param>
 /// <returns>Dictionary of all supported commands with their handlers</returns>
 private static IReadOnlyDictionary <string, IFtpCommand> GetSupportedCommands(FtpServerOptions serverOptions)
 {
     return
         (new Dictionary <string, IFtpCommand>(StringComparer.OrdinalIgnoreCase)
     {
         { FtpCommands.User, new UserCommand(serverOptions.Users) },
         { FtpCommands.Password, new PasswordCommand(serverOptions.Users) },
         { FtpCommands.SystemType, new SystemTypeCommand() },
         { FtpCommands.Features,
           new FeaturesCommand(
               new[]
             {
                 FtpOptions.UTF8,
                 FtpOptions.UTF_8,
                 FtpCommands.ModifiedTime,
                 FtpCommands.FileSize,
                 FtpOptions.RestartableFileTransfer
             }) },
         { FtpCommands.Options, new OptionsCommand() },
         { FtpCommands.PrintWorkingDirectory, new PrintWorkingDirectoryCommand() },
         { FtpCommands.PrintWorkingDirectoryExtended, new PrintWorkingDirectoryCommand() },
         { FtpCommands.ChangeWorkingDirectory, new ChangeWorkingDirectoryCommand() },
         { FtpCommands.ChangeWorkingDirectoryExtended, new ChangeWorkingDirectoryCommand() },
         { FtpCommands.ChangeDirectoryUp, new ChangeDirectoryUpCommand() },
         { FtpCommands.ChangeDirectoryUpExtended, new ChangeDirectoryUpCommand() },
         { FtpCommands.TransferType, new TransferTypeCommand() },
         { FtpCommands.TransferMode, new TransferModeCommand() },
         { FtpCommands.FileStructure, new FileStructureCommand() },
         { FtpCommands.PassiveMode, new PassiveModeCommand() },
         { FtpCommands.Port, new PortCommand() },
         { FtpCommands.ListFiles, new ListFilesCommand() },
         { FtpCommands.ListFileNames, new ListFileNamesCommand() },
         { FtpCommands.ModifiedTime, new ModifiedTimeCommand() },
         { FtpCommands.FileSize, new FileSizeCommand() },
         { FtpCommands.RenameFrom, new RenameFromCommand() },
         { FtpCommands.RenameTo, new RenameToCommand() },
         { FtpCommands.AppendFile, new AppendFileCommand() },
         { FtpCommands.StoreFile, new StoreFileCommand() },
         { FtpCommands.RetrieveFile, new RetrieveFileCommand() },
         { FtpCommands.RestartFileTransfer, new RestartFileTransferCommand() },
         { FtpCommands.AbortFileTransfer, new AbortFileTransferCommand() },
         { FtpCommands.DeleteFile, new DeleteFileCommand() },
         { FtpCommands.MakeDirectory, new MakeDirectoryCommand() },
         { FtpCommands.MakeDirectoryExtended, new MakeDirectoryCommand() },
         { FtpCommands.RemoveDirectory, new RemoveDirectoryCommand() },
         { FtpCommands.RemoveDirectoryExtended, new RemoveDirectoryCommand() },
         { FtpCommands.Allocate, new AllocateCommand() },
         { FtpCommands.NoOperation, new NoOperationCommand() },
         { FtpCommands.Reinitialize, new ReinitializeCommand() },
         { FtpCommands.Quit, new QuitCommand() },
     });
 }