#!/usr/bin/env ruby

module Ftpd
  class FtpServer < TlsServer

    DEFAULT_SERVER_NAME = 'wconrad/ftpd'
    DEFAULT_SESSION_TIMEOUT = 300 # seconds

    # The number of seconds to delay before replying.  This is for
    # testing, when you need to test, for example, client timeouts.
    # Defaults to 0 (no delay).
    #
    # Change to this attribute only take effect for new sessions.

    attr_accessor :response_delay

    # The class for formatting for LIST output.  Defaults to
    # {Ftpd::ListFormat::Ls}.  Changes to this attribute only take
    # effect for new sessions.

    attr_accessor :list_formatter

    # @return [Integer] The authentication level
    # One of:
    # * Ftpd::AUTH_USER
    # * Ftpd::AUTH_PASSWORD (default)
    # * Ftpd::AUTH_ACCOUNT

    attr_accessor :auth_level

    # The session timeout.  When a session is awaiting a command, if
    # one is not received in this many seconds, the session is
    # disconnected.  Defaults to {DEFAULT_SESSION_TIMEOUT}.  If nil,
    # then timeout is disabled.
    # @return [Numeric]

    attr_accessor :session_timeout

    # The server's name, sent in a STAT reply.  Defaults to
    # {DEFAULT_SERVER_NAME}.

    attr_accessor :server_name

    # The server's version, sent in a STAT reply.  Defaults to the
    # contents of the VERSION file.

    attr_accessor :server_version

    # The logger.  Defaults to nil (no logging).
    # @return [Logger]

    attr_accessor :log

    # Allow PORT command to specify data ports below 1024.  Defaults
    # to false.  Setting this to true makes it easier for an attacker
    # to use the server to attack another server.  See RFC 2577
    # section 3.
    # @return [Boolean]

    attr_accessor :allow_low_data_ports

    # Create a new FTP server.  The server won't start until the
    # #start method is called.
    #
    # @param driver A driver for the server's dynamic behavior such as
    #               authentication and file system access.
    #
    # The driver should expose these public methods:
    # * {Example::Driver#authenticate authenticate}
    # * {Example::Driver#file_system file_system}

    def initialize(driver)
      super()
      @driver = driver
      @response_delay = 0
      @list_formatter = ListFormat::Ls
      @auth_level = AUTH_PASSWORD
      @session_timeout = 300
      @server_name = DEFAULT_SERVER_NAME
      @server_version = read_version_file
      @allow_low_data_ports = false
      @log = nil
    end

    private

    def session(socket)
      Session.new(:socket => socket,
                  :driver => @driver,
                  :list_formatter => @list_formatter,
                  :response_delay => response_delay,
                  :tls => @tls,
                  :auth_level => @auth_level,
                  :session_timeout => @session_timeout,
                  :server_name => @server_name,
                  :server_version => @server_version,
                  :log => log,
                  :allow_low_data_ports => allow_low_data_ports).run
    end

    def read_version_file
      File.open(version_file_path, 'r', &:read).strip
    end

    def version_file_path
      File.expand_path('../../VERSION', File.dirname(__FILE__))
    end

  end
end