lib/ftpd/telnet.rb in ftpd-0.9.0 vs lib/ftpd/telnet.rb in ftpd-0.10.0

- old
+ new

@@ -48,11 +48,11 @@ # Create a new instance with a command that may contain Telnet # sequences. # @param command [String] def initialize(command) - telnet_state_machine command + parse_command command end private module Codes @@ -64,54 +64,49 @@ IP = 244.chr # 0xf4 DM = 242.chr # 0xf2 end include Codes - def telnet_state_machine (command) + def accept(scanner) + @plain << scanner[1] + end + + def reply_dont(scanner) + @reply << IAC + DONT + scanner[1] + end + + def reply_wont(scanner) + @reply << IAC + WONT + scanner[1] + end + + def ignore(scanner) + end + + # Telnet sequences to handle, and how to handle them + + SEQUENCES = [ + [/#{IAC}(#{IAC})/, :accept], + [/#{IAC}#{WILL}(.)/m, :reply_dont], + [/#{IAC}#{WONT}(.)/m, :ignore], + [/#{IAC}#{DO}(.)/m, :reply_wont], + [/#{IAC}#{DONT}(.)/m, :ignore], + [/#{IAC}#{IP}/, :ignore], + [/#{IAC}#{DM}/, :ignore], + [/(.)/m, :accept], + ] + + # Parse the the command. Sets @plain and @reply + + def parse_command(command) @plain = '' @reply = '' - state = :idle - command.each_char do |c| - case state - when :idle - if c == IAC - state = :iac - else - @plain << c + scanner = StringScanner.new(command) + while !scanner.eos? + SEQUENCES.each do |regexp, method| + if scanner.scan(regexp) + send method, scanner + break end - when :iac - case c - when IAC - @plain << c - state = :idle - when WILL - state = :will - when WONT - state = :wont - when DO - state = :do - when DONT - state = :dont - when IP - state = :idle - when DM - state = :idle - else - @plain << IAC + c - state = :idle - end - when :will - @reply << IAC + DONT + c - state = :idle - when :wont - state = :idle - when :do - @reply << IAC + WONT + c - state = :idle - when :dont - state = :idle - else - raise "Unknown state #{state.inspect}" end end end end