# File lib/network/protocol/terminalfilter.rb, line 47
  def filter_in(str)
    buf = ""
    str.each_byte do |b|
      case mode?
      when :ground
        case b
        when 0x20..0x7e
          buf << b.chr
        when ESC
          log.debug("(#{@pstack.conn.object_id}) ESC found")
          @collect = ""
          set_mode :escape
        # These cause immediate execution no matter what mode
        when ENQ, BEL, BS, TAB, VT, FF, SO, SI, DC1, DC3, CAN, SUB, DEL
          case b
          when BS, DEL
            log.debug("(#{@pstack.conn.object_id}) BS, DEL found")
            # slice local buffer or connection buffer
            buf.slice!(-1) || @pstack.conn.inbuffer.slice!(-1)
          when CAN, SUB
            @collect = ""
            set_mode :ground
          else
            buf << execute(b)
          end
        else
          buf << b.chr
        end
      when :escape
        case b
        when ?[
          log.debug("(#{@pstack.conn.object_id}) CSI sequence found")
          set_mode :csi
        when ?]
          log.debug("(#{@pstack.conn.object_id}) OSC/XTERM sequence found")
          set_mode :xterm
        when ?P
          log.debug("(#{@pstack.conn.object_id}) DCS sequence found")
          set_mode :dcs
        when ?O
          log.debug("(#{@pstack.conn.object_id}) SS3 sequence found")
          set_mode :ss3
        when ?X, ?^, ?_
          log.debug("(#{@pstack.conn.object_id}) SOS/PM/APC sequence found")
          set_mode :sospmapc
        when ?D
          buf << "[SCROLLDOWN]"
          set_mode :ground
        when ?M
          buf << "[SCROLLUP]"
          set_mode :ground
        # VT52
        when ?A
          buf << "[UP 1]"
          set_mode :ground
        when ?B
          buf << "[DOWN 1]"
          set_mode :ground
        when ?C
          buf << "[RIGHT 1]"
          set_mode :ground
        when ?D
          buf << "[LEFT 1]"
          set_mode :ground
        # /VT52
#        when ?H # Set tab at current position - ignored
#        when ?E # Next line - like CRLF?
#        when ?7 # Save cursor and attributes SCURA
#        when ?8 # Restore cursor and attributes RCURA
#        when ?c # reset device
        # These cause immediate execution no matter what mode
        when ENQ, BEL, BS, TAB, VT, FF, SO, SI, DC1, DC3, CAN, SUB, DEL
          case b
          when BS, DEL
            log.debug("(#{@pstack.conn.object_id}) BS, DEL found")
            # slice local buffer or connection buffer
            buf.slice!(-1) || @pstack.conn.inbuffer.slice!(-1)
          when CAN, SUB
            @collect = ""
            set_mode :ground
          else
            buf << execute(b)
          end
        when 0x20..0x2F  # " !"#$%&'()*+,-./"
          @collect << b.chr
          set_mode :escint
        else
# These should all be immediately dispatched and sent to ground mode
#        when "0123456789:;<=>?@ABCDEFGHIJKLMNO" 0x30..0x4F
#        when "QRSTUVW" 0x51..0x57
#        when "YZ" 0x59..0x5A
#        when "\\" 0x5C
#        when "`abcdefghijklmnopqrstuvwxyz{|}~" 0x60..0x7e
          set_mode :ground
        end
      when :escint
#        case b
#        when ?( # Set default font
#        when ?) # Set alternate font
           # both ( and ) may be followed by A,B,0,1,2  !!
#        end
         set_mode :ground
      when :dcs
# terminated by ST or ESC           set_mode :ground
      when :xterm
         set_mode :ground
      when :sospmapc
         set_mode :ground
      when :csi
        case b
        when ?A
          buf << "[UP #{@collect.to_i == 0 ? 1 : @collect.to_i}]"
          set_mode :ground
        when ?B
          buf << "[DOWN #{@collect.to_i == 0 ? 1 : @collect.to_i}]"
          set_mode :ground
        when ?C
          buf << "[RIGHT #{@collect.to_i == 0 ? 1 : @collect.to_i}]"
          set_mode :ground
        when ?D
          buf << "[LEFT #{@collect.to_i == 0 ? 1 : @collect.to_i}]"
          set_mode :ground
        when ?H, ?f  # set cursor position \e[H or \e[<row>;<col>H
          a = @collect.split(";")
          a = ["1","1"] if a.empty?
          buf << "[HOME #{a[0]},#{a[1]}]"
          set_mode :ground
        when ?R # report cursor pos
          a = @collect.split(";")
          a = ["1","1"] if a.empty?
          buf << "[CURSOR #{a[0]},#{a[1]}]"
          set_mode :ground
        when ?r # Set scrolling region
          # Enable scrolling entire display \e[r or just a region \e[<srow>;<erow>r
          a = @collect.split(";")
          if a.empty?  # lines numbered from 1
            # This should be 1 to n or the whole screen if no parms
            buf << "[SCRRESET]"
          else
            buf << "[SCRREG #{a[0]},#{a[1]}]"
          end
          set_mode :ground
        when ?J
          if @collect.to_i == 2
            buf << "[CLEAR]"
          end
          set_mode :ground
#     Erase from cursor to end of screen         Esc [ 0 J    or Esc [ J
#     Erase from beginning of screen to cursor   Esc [ 1 J
#     Erase entire screen                        Esc [ 2 J
        when ?K
          if @collect.to_i == 2
            buf << "[CLEARLINE]"
          end
          set_mode :ground
#        when ?K  Erase line
#     Erase from cursor to end of line           Esc [ 0 K    or Esc [ K
#     Erase from beginning of line to cursor     Esc [ 1 K
#     Erase line containing cursor               Esc [ 2 K
        when ?G
          buf << "[POS #{@collect.to_i == 0 ? 1 : @collect.to_i}]"
          set_mode :ground
#        when ?G  Set starting column of presentation

        when ?g, ?c, ?h, ?l, ?s, ?u, ?x, ?y, ?q, ?i, ?p
          # unhandled
          set_mode :ground
#        when ?c  DA request/response - Device code - response is \e[<code>0c


#        when ?g  Tab clear at current position
#  CSI 3 g is clear all tabs

#        when ?h  Set mode
#        when ?l  Reset mode
# Enable Line Wrap  <ESC>[7h
# Disable Line Wrap <ESC>[7l

#        when ?s  save cursor
#        when ?u  unsave cursor
#  Same as ESC7 and ESC8 but not attributes?

#        when ?x  Report terminal parameters
#        when ?y  Confidence test
#        when ?q  load LEDs
#        when ?i  printing
#        when ?p  Set Key Definition  <ESC>[{key};"{string}"p

#        when ?P # -> set_mode :dcs


        when ?n  # Device status request
          i = @collect.to_i
          if i == 6  # Query cursor position - response is \e[<row>;<col>R
            # request for report cursor pos
            buf << "[CURREPT]"
          end
          set_mode :ground
        when ?m  # SGR color
          a = @collect.split(";")
          a.each do |cd|
            s = SGR2CODE[cd]
            buf << s if s
          end
          set_mode :ground
        when ?~  # keys
          i = @collect.to_i
          case i
          when 1, 7
            buf << "[HOME 1,1]"
          when 2
            buf << "[INSERT]"
          when 3  # delete
            log.debug("(#{@pstack.conn.object_id}) BS, DEL found")
            buf.slice!(-1) || @pstack.conn.inbuffer.slice!(-1)
            echo(BS.chr)
          when 4, 8
            buf << "[END]"
          when 5
            buf << "[PAGEUP]"
          when 6
            buf << "[PAGEDOWN]"
          when 11
            buf << "[F1]"
          when 12
            buf << "[F2]"
          when 13
            buf << "[F3]"
          when 14
            buf << "[F4]"
          when 15
            buf << "[F5]"
          when 17
            buf << "[F6]"
          when 18
            buf << "[F7]"
          when 19
            buf << "[F8]"
          when 20
            buf << "[F9]"
          when 21
            buf << "[F10]"
          end
          set_mode :ground
        # These cause immediate execution no matter what mode
        when ENQ, BEL, BS, TAB, VT, FF, SO, SI, DC1, DC3, CAN, SUB, DEL
          case b
          when BS, DEL
            log.debug("(#{@pstack.conn.object_id}) BS, DEL found")
            # slice local buffer or connection buffer
            buf.slice!(-1) || @pstack.conn.inbuffer.slice!(-1)
          when CAN, SUB
            @collect = ""
            set_mode :ground
          else
            buf << execute(b)
          end
        else
          @collect << b.chr
        end
      when :ss3
        case b
        # Windows XP telnet
        when ?P
          buf << "[F1]"
        when ?Q
          buf << "[F2]"
        when ?R
          buf << "[F3]"
        when ?S
          buf << "[F4]"
        # /Windows XP telnet
        # ANSI cursor key mode
        when ?A
          buf << "[UP 1]"
        when ?B
          buf << "[DOWN 1]"
        when ?C
          buf << "[RIGHT 1]"
        when ?D
          buf << "[LEFT 1]"
        # /ANSI cursor key mode
        # These cause immediate execution no matter what mode
        when ENQ, BEL, BS, TAB, VT, FF, SO, SI, DC1, DC3, CAN, SUB, DEL
          case b
          when BS, DEL
            log.debug("(#{@pstack.conn.object_id}) BS, DEL found")
            # slice local buffer or connection buffer
            buf.slice!(-1) || @pstack.conn.inbuffer.slice!(-1)
          when CAN, SUB
            @collect = ""
            set_mode :ground
          else
            buf << execute(b)
          end
        end
        set_mode :ground
      end
    end  # eachwhile b

    buf
  end