tmud-3.0.0/benchmark/
tmud-3.0.0/cmd/
tmud-3.0.0/cmd/objects/
tmud-3.0.0/cmd/tiny/
tmud-3.0.0/doc/SQLite/
tmud-3.0.0/doc/SQLite3/
tmud-3.0.0/doc/TernaryTrie/
tmud-3.0.0/farts/
tmud-3.0.0/lib/
tmud-3.0.0/lib/engine/
tmud-3.0.0/lib/farts/
tmud-3.0.0/logs/
#
# file::    telnetfilter.rb
# author::  Jon A. Lambert
# version:: 2.8.0
# date::    01/19/2006
#
# This source code copyright (C) 2005, 2006 by Jon A. Lambert
# All rights reserved.
#
# Released under the terms of the TeensyMUD Public License
# See LICENSE file for additional information.
#
$:.unshift "lib" if !$:.include? "lib"
$:.unshift "vendor" if !$:.include? "vendor"

require 'strscan'
require 'ostruct'
require 'network/protocol/filter'
require 'network/protocol/telnetcodes'
require 'network/protocol/asciicodes'

# The TelnetFilter class implements the Telnet protocol.
#
# This implements most of basic Telnet as per RFCs 854/855/1129/1143 and
# options in RFCs 857/858/1073/1091
#
class TelnetFilter < Filter
  include ASCIICodes
  include TelnetCodes

  logger 'DEBUG'

  # Initialize state of filter
  #
  # [+pstack+] The ProtocolStack associated with this filter
  # [+server+] An optional hash of desired initial options
  def initialize(pstack, server)
    super(pstack)
    @server = server
    @wopts = {}
    getopts(@server.service_negotiation)
    @mode = :normal #  Parse mode :normal, :cmd, :cr
    @state = {}
    @sc = nil
    @sneg_opts = [ TTYPE, ZMP ]  # supported options which imply an initial
                                 # sub negotiation of options
    @ttype = []
    @init_tries = 0   # Number of tries at negotitating sub options
    @synch = false
    log.debug "telnet filter initialized - #{@init_tries}"
  end

  # Negotiate starting wanted options
  #
  # [+args+] Optional initial options
  def init(args)
    if @server.service_type == :client  # let server offer and ask for client
      # several sorts of options here - server offer, ask client or both
      @wopts.each do |key,val|
        case key
        when ECHO, SGA, BINARY, ZMP, EOREC
          ask_him(key,val)
        else
          offer_us(key,val)
        end
      end
    else
      # several sorts of options here - server offer, ask client or both
      @wopts.each do |key,val|
        case key
        when ECHO, SGA, BINARY, ZMP, EOREC
          offer_us(key,val)
        else
          ask_him(key,val)
        end
      end
    end
    true
  end

  # The filter_in method filters input data
  # [+str+]    The string to be processed
  # [+return+] The filtered data
  def filter_in(str)
#    init_subneg
    return "" if str.nil? || str.empty?
    buf = ""

    @sc ? @sc.concat(str) : @sc = StringScanner.new(str)
    while b = @sc.get_byte

      # OOB sync data
      if @pstack.urgent_on || b.getbyte(0) == DM
        log.debug("(#{@pstack.conn.object_id}) Sync mode on")
        @pstack.urgent_on = false
        @synch = true
        break
      end

      case mode?
      when :normal
        case b.getbyte(0)
        when CR
          next if @synch
          set_mode(:cr) if !@pstack.binary_on
        when LF  # LF or LF/CR may be issued by broken mud servers and clients
          next if @synch
          set_mode(:lf) if !@pstack.binary_on
          buf << LF.chr
          echo(CR.chr + LF.chr)
        when IAC
          set_mode(:cmd)
        when NUL  # ignore NULs in stream when in normal mode
          next if @synch
          if @pstack.binary_on
            buf << b
            echo(b)
          else
            log.debug("(#{@pstack.conn.object_id}) unexpected NUL found in stream")
          end
        when BS, DEL
          next if @synch
          # Leaves BS, DEL in input stream for higher filter to deal with.
          buf << b
          echo(BS.chr)
        else
          next if @synch
          ### NOTE - we will allow 8-bit NVT against RFC 1123 recommendation "should not"
          ###
          # Only let 7-bit values through in normal mode
          #if (b[0] & 0x80 == 0) && !@pstack.binary_on
            buf << b
            echo(b)
          #else
          #  log.debug("(#{@pstack.conn.object_id}) unexpected 8-bit byte found in stream '#{b[0]}'")
          #end
        end
      when :cr
        # handle CRLF and CRNUL by insertion of LF into buffer
        case b.getbyte(0)
        when LF
          buf << LF.chr
          echo(CR.chr + LF.chr)
        when NUL
          if @server.service_type == :client  # Don't xlate CRNUL when client
            buf << CR.chr
            echo(CR.chr)
          else
            buf << LF.chr
            echo(CR.chr + LF.chr)
          end
        else # eat lone CR
          buf << b
          echo(b)
        end
        set_mode(:normal)
      when :lf
        # liberally handle LF, LFCR for clients that aren't telnet correct
        case b.getbyte(0)
        when CR # Handle LFCR by swallowing CR
        else  # Handle other stuff that follows - single LF
          buf << b
          echo(b)
        end
        set_mode(:normal)
      when :cmd
        case b.getbyte(0)
        when IAC
          # IAC escapes IAC
          buf << IAC.chr
          set_mode(:normal)
        when AYT
          log.debug("(#{@pstack.conn.object_id}) AYT sent - Msg returned")
          @pstack.conn.sock.send("TeensyMUD is here.\n",0)
          set_mode(:normal)
        when AO
          log.debug("(#{@pstack.conn.object_id}) AO sent - Synch returned")
          @pstack.conn.sockio.write_flush
          @pstack.conn.sock.send(IAC.chr + DM.chr, 0)
          @pstack.conn.sockio.write_urgent(DM.chr)
          set_mode(:normal)
        when IP
          @pstack.conn.sockio.read_flush
          @pstack.conn.sockio.write_flush
          log.debug("(#{@pstack.conn.object_id}) IP sent")
          set_mode(:normal)
        when GA, NOP, BRK  # not implemented or ignored
          log.debug("(#{@pstack.conn.object_id}) GA, NOP or BRK sent")
          set_mode(:normal)
        when DM
          log.debug("(#{@pstack.conn.object_id}) Synch mode off")
          @synch = false
          set_mode(:normal)
        when EC
          next if @synch
          log.debug("(#{@pstack.conn.object_id}) EC sent")
          if buf.size > 1
            buf.slice!(-1)
          elsif @pstack.conn.inbuffer.size > 0
            @pstack.conn.inbuffer.slice(-1)
          end
          set_mode(:normal)
        when EL
          next if @synch
          log.debug("(#{@pstack.conn.object_id}) EL sent")
          p = buf.rindex("\n")
          if p
            buf.slice!(p+1..-1)
          else
            buf = ""
            p = @pstack.conn.inbuffer.rindex("\n")
            if p
              @pstack.conn.inbuffer.slice!(p+1..-1)
            end
          end
          set_mode(:normal)
        when DO, DONT, WILL, WONT
          if @sc.eos?
            @sc.unscan
            break
          end
          opt = @sc.get_byte
          case b.getbyte(0)
          when WILL
            replies_him(opt.getbyte(0),true)
          when WONT
            replies_him(opt.getbyte(0),false)
          when DO
            requests_us(opt.getbyte(0),true)
          when DONT
            requests_us(opt.getbyte(0),false)
          end
          # Update interesting things in ProtocolStack after negotiation
          case opt.getbyte(0)
          when ECHO
            @pstack.echo_on = enabled?(ECHO, :us)
          when BINARY
            @pstack.binary_on = enabled?(BINARY, :us)
          when ZMP
            @pstack.zmp_on = enabled?(ZMP, :us)
          end
          set_mode(:normal)
        when SB
          @sc.unscan
          break if @sc.check_until(/#{IAC.chr}#{SE.chr}/).nil?
          @sc.get_byte
          opt = @sc.get_byte
          data = @sc.scan_until(/#{IAC.chr}#{SE.chr}/).chop.chop
          parse_subneg(opt.getbyte(0),data)
          set_mode(:normal)
        else
          log.debug("(#{@pstack.conn.object_id}) Unknown Telnet command - #{b.getbyte(0)}")
          set_mode(:normal)
        end
      end
    end  # while b

    @sc = nil if @sc.eos?
    buf
  end

  # The filter_out method filters output data
  # [+str+]    The string to be processed
  # [+return+] The filtered data
  def filter_out(str)
    return '' if str.nil? || str.empty?
    if !@pstack.binary_on
      str.gsub!(/\n/, "\r\n")
    end
    str
  end

  ###### Custom public methods

  # Test to see if option is enabled
  # [+opt+] The Telnet option code
  # [+who+] The side to check :us or :him
  def enabled?(opt, who)
    option(opt)
    e = @state[opt].send(who)
    e == :yes ? true : false
  end

  # Test to see which state we prefer this option to be in
  # [+opt+] The Telnet option code
  def desired?(opt)
    st = @wopts[opt]
    st = false if st.nil?
    st
  end

  # Handle server-side echo
  # [+ch+] character string to echo
  def echo(ch)
    return if @server.service_type == :client  # Never echo for server when client
                                  # Remove this if it makes sense for peer to peer
    if @pstack.echo_on
      if @pstack.hide_on && ch.getbyte(0) != CR
        @pstack.conn.sock.send('*',0)
      else
        @pstack.conn.sock.send(ch,0)
      end
    end
  end

  # Negotiate starting wanted options that imply subnegotation
  # So far only terminal type
  def init_subneg
    return if @init_tries > 20
    @init_tries += 1
    @wopts.each_key do |opt|
      next if !@sneg_opts.include?(opt)
      log.debug("(#{@pstack.conn.object_id}) Subnegotiation attempt for option #{opt}.")
      case opt
      when TTYPE
        who = :him
      else
        who = :us
      end
      if desired?(opt) == enabled?(opt, who)
        case opt
        when TTYPE
          @pstack.conn.sendmsg(IAC.chr + SB.chr + TTYPE.chr + 1.chr + IAC.chr + SE.chr)
        when ZMP
          log.info("(#{@pstack.conn.object_id}) ZMP successfully negotiated." )
          @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
            "zmp.check#{NUL.chr}color.#{NUL.chr}" +
            "#{IAC.chr}#{SE.chr}")
          @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
            "zmp.ident#{NUL.chr}TeensyMUD#{NUL.chr}#{Version}#{NUL.chr}A sexy mud server#{NUL.chr}" +
            "#{IAC.chr}#{SE.chr}")
          @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
            "zmp.ping#{NUL.chr}" +
            "#{IAC.chr}#{SE.chr}")
          @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
            "zmp.input#{NUL.chr}\n     I see you support...\n     ZMP protocol\n#{NUL.chr}" +
            "#{IAC.chr}#{SE.chr}")
        end
        @sneg_opts.delete(opt)
      end
    end

    if @init_tries > 20
      log.debug("(#{@pstack.conn.object_id}) Telnet init_subneg option - Timed out after #{@init_tries} tries.")
      @sneg_opts = []
      @pstack.conn.set_initdone
      if !@pstack.terminal or @pstack.terminal.empty?
        @pstack.terminal = "dumb"
      end
    end
  end

  def send_naws
    return if !enabled?(NAWS, :us)
    ts = @pstack.query(:termsize)
    data = [ts[0]].pack('n') + [ts[1]].pack('n')
    data.gsub!(/#{IAC}/, IAC.chr + IAC.chr) # 255 needs to be doubled
    @pstack.conn.sendmsg(IAC.chr + SB.chr + NAWS.chr + data + IAC.chr + SE.chr)
  end

private
  ###### Private methods

  def getopts(wopts)
    # supported options
    wopts.each do |op|
      case op
      when :ttype
        @wopts[TTYPE] = true
      when :echo
        @wopts[ECHO] = true
      when :sga
        @wopts[SGA] = true
      when :naws
        @wopts[NAWS] = true
      when :eorec
        @wopts[EOREC] = true
      when :binary
        @wopts[BINARY] = true
      when :zmp
        @wopts[ZMP] = true
      end
    end
  end

  # parse the subnegotiation data and save it
  # [+opt+] The Telnet option found
  # [+data+] The data found between SB OPTION and IAC SE
  def parse_subneg(opt,data)
    data.gsub!(/#{IAC}#{IAC}/, IAC.chr) # 255 needs to be undoubled from all data
    case opt
    when NAWS
      @pstack.twidth = data[0..1].unpack('n')[0]
      @pstack.theight = data[2..3].unpack('n')[0]
      @pstack.conn.publish(:termsize)
      log.debug("(#{@pstack.conn.object_id}) Terminal width #{@pstack.twidth} / height #{@pstack.theight}")
    when TTYPE
      if data.getbyte(0) == 0
        log.debug("(#{@pstack.conn.object_id}) Terminal type - #{data[1..-1]}")
        if !@ttype.include?(data[1..-1])
          # short-circuit choice because of Zmud
          if data[1..-1].downcase == 'zmud'
            @ttype << data[1..-1]
            @pstack.terminal = 'zmud'
            log.debug("(#{@pstack.conn.object_id}) Terminal choice - #{@pstack.terminal} in list #{@ttype.inspect}")
          end
          # short-circuit choice because of Windows telnet client
          if data[1..-1].downcase == 'vt100'
            @ttype << data[1..-1]
            @pstack.terminal = 'vt100'
            log.debug("(#{@pstack.conn.object_id}) Terminal choice - #{@pstack.terminal} in list #{@ttype.inspect}")
          end
          return if @pstack.terminal
          @ttype << data[1..-1]
          @pstack.conn.sendmsg(IAC.chr + SB.chr + TTYPE.chr + 1.chr + IAC.chr + SE.chr)
        else
          return if @pstack.terminal
          choose_terminal
        end
      elsif data.getbyte(0) == 1  # send - should only be called by :client
        return if !@pstack.terminal
        @pstack.conn.sendmsg(IAC.chr + SB.chr + TTYPE.chr + 0.chr + @pstack.terminal + IAC.chr + SE.chr)
      end
    when ZMP
      args = data.split("\0")
      cmd = args.shift
      handle_zmp(cmd,args)
    end
  end

  # Pick a preferred terminal
  # Order is vt100, vt999, ansi, xterm, or a recognized custom client
  # Should not pick vtnt as we dont handle it
  def choose_terminal
    if @ttype.empty?
      @pstack.terminal = "dumb"
    end

    # Pick most capable from list of terminals
    @pstack.terminal = @ttype.find {|t| t =~ /mushclient/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /simplemu/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /(zmud).*/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /linux/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /cygwin/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /(cons25).*/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /(xterm).*/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~  /(vt)[-]?100/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /(vt)[-]?\d+/i } if !@pstack.terminal
    @pstack.terminal = @ttype.find {|t| t =~ /(ansi).*/i } if !@pstack.terminal

    if @pstack.terminal && @ttype.last != @pstack.terminal # short circuit retraversal of options
      @ttype.each do |t|
        @pstack.conn.sendmsg(IAC.chr + SB.chr + TTYPE.chr + 1.chr + IAC.chr + SE.chr)
        break if t == @pstack.terminal
      end
    elsif @ttype.last != @pstack.terminal
      @pstack.terminal = 'dumb'
    end

    @pstack.terminal.downcase!

    # translate certain terminals to something meaningful
    case @pstack.terminal
    when /cygwin/i, /cons25/i, /linux/i, /dec-vt/i
      @pstack.terminal = 'vt100'
    when /ansis/i then
      @pstack.terminal = 'ansi'
    end
    log.debug("(#{@pstack.conn.object_id}) Terminal set to - #{@pstack.terminal} from list #{@ttype.inspect}")
  end

  # Get current parse mode
  # [+return+] The current parse mode
  def mode?
    return @mode
  end

  # set current parse mode
  # [+m+] Mode to set it to
  def set_mode(m)
    @mode = m
  end

  # Creates an option entry in our state table and sets its initial state
  def option(opt)
    return if @state.key?(opt)
    o = OpenStruct.new
    o.us = :no
    o.him = :no
    o.usq = :empty
    o.himq = :empty
    @state[opt] = o
  end

  # Ask the client to enable or disable an option.
  #
  # [+opt+]   The option code
  # [+enable+] true for enable, false for disable
  def ask_him(opt, enable)
    log.debug("(#{@pstack.conn.object_id}) Requested Telnet option #{opt.to_s} set to #{enable.to_s}")
    initiate(opt, enable, :him)
  end

  # Offer the server to enable or disable an option
  #
  # [+opt+]   The option code
  # [+enable+] true for enable, false for disable
  def offer_us(opt, enable)
    log.debug("(#{@pstack.conn.object_id}) Offered Telnet option #{opt.to_s} set to #{enable.to_s}")
    initiate(opt, enable, :us)
  end

  # Initiate a request to client.  Called by ask_him or offer_us.
  #
  # [+opt+]   The option code
  # [+enable+] true for enable, false for disable
  # [+who+] :him if asking client, :us if server offering
  def initiate(opt, enable, who)
    option(opt)

    case who
    when :him
      willdo = DO.chr
      wontdont = DONT.chr
      whoq = :himq
    when :us
      willdo = WILL.chr
      wontdont = WONT.chr
      whoq = :usq
    else
      # Error
    end

    case @state[opt].send(who)
    when :no
      if enable
        @state[opt].send("#{who}=", :wantyes)
        @pstack.conn.sendmsg(IAC.chr + willdo + opt.chr)
      else
        # Error already disabled
        log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} already disabled")
      end
    when :yes
      if enable
        # Error already enabled
        log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} already enabled")
      else
        @state[opt].send("#{who}=", :wantno)
        @pstack.conn.sendmsg(IAC.chr + wontdont + opt.chr)
      end
    when :wantno
      if enable
        case @state[opt].send(whoq)
        when :empty
          @state[opt].send("#{whoq}=", :opposite)
        when :opposite
          # Error already queued enable request
          log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} already queued enable request")
        end
      else
        case @state[opt].send(whoq)
        when :empty
          # Error already negotiating for disable
          log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} already negotiating for disable")
        when :opposite
          @state[opt].send("#{whoq}=", :empty)
        end
      end
    when :wantyes
      if enable
        case @state[opt].send(whoq)
        when :empty
          #Error already negotiating for enable
          log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} already negotiating for enable")
        when :opposite
          @state[opt].send("#{whoq}=", :empty)
        end
      else
        case @state[opt].send(whoq)
        when :empty
          @state[opt].send("#{whoq}=", :opposite)
        when :opposite
          #Error already queued for disable request
          log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} already queued for disable request")
        end
      end
    end
  end

  # Client replies WILL or WONT
  #
  # [+opt+]   The option code
  # [+enable+] true for WILL answer, false for WONT answer
  def replies_him(opt, enable)
    log.debug("(#{@pstack.conn.object_id}) Client replies to Telnet option #{opt.to_s} set to #{enable.to_s}")
    response(opt, enable, :him)
  end

  # Client requests DO or DONT
  #
  # [+opt+]   The option code
  # [+enable+] true for DO request, false for DONT request
  def requests_us(opt, enable)
    log.debug("(#{@pstack.conn.object_id}) Client requests Telnet option #{opt.to_s} set to #{enable.to_s}")
    response(opt, enable, :us)
  end

  # Handle client response.  Called by requests_us or replies_him
  #
  # [+opt+]   The option code
  # [+enable+] true for WILL answer, false for WONT answer
  # [+who+] :him if client replies, :us if client requests
  def response(opt, enable, who)
    option(opt)

    case who
    when :him
      willdo = DO.chr
      wontdont = DONT.chr
      whoq = :himq
    when :us
      willdo = WILL.chr
      wontdont = WONT.chr
      whoq = :usq
    else
      # Error
    end

    case @state[opt].send(who)
    when :no
      if enable
        if desired?(opt)
        # If we agree
          @state[opt].send("#{who}=", :yes)
          @pstack.conn.sendmsg(IAC.chr + willdo + opt.chr)
          log.debug("(#{@pstack.conn.object_id}) Telnet negotiation: agreed to enable option #{opt}")
        else
        # If we disagree
          @pstack.conn.sendmsg(IAC.chr + wontdont + opt.chr)
          log.debug("(#{@pstack.conn.object_id}) Telnet negotiation: disagreed to enable option #{opt}")
        end
      else
        # Ignore
      end
    when :yes
      if enable
        # Ignore
      else
        @state[opt].send("#{who}=", :no)
        @pstack.conn.sendmsg(IAC.chr + wontdont + opt.chr)
      end
    when :wantno
      if enable
        case @state[opt].send(whoq)
        when :empty
          #Error DONT/WONT answered by WILL/DO
          @state[opt].send("#{who}=", :no)
        when :opposite
          #Error DONT/WONT answered by WILL/DO
          @state[opt].send("#{who}=", :yes)
          @state[opt].send("#{whoq}=", :empty)
        end
        log.error("(#{@pstack.conn.object_id}) Telnet negotiation: option #{opt.to_s} DONT/WONT answered by WILL/DO")
      else
        case @state[opt].send(whoq)
        when :empty
          @state[opt].send("#{who}=", :no)
          log.debug("(#{@pstack.conn.object_id}) Telnet negotiation: agreed to disable option #{opt}")
        when :opposite
          @state[opt].send("#{who}=", :wantyes)
          @state[opt].send("#{whoq}=", :empty)
          @pstack.conn.sendmsg(IAC.chr + willdo + opt.chr)
        end
      end
    when :wantyes
      if enable
        case @state[opt].send(whoq)
        when :empty
          @state[opt].send("#{who}=", :yes)
          log.debug("(#{@pstack.conn.object_id}) Telnet negotiation: agreed to enable option #{opt}")
        when :opposite
          @state[opt].send("#{who}=", :wantno)
          @state[opt].send("#{whoq}=", :empty)
          @pstack.conn.sendmsg(IAC.chr + wontdont + opt.chr)
        end
      else
        case @state[opt].send(whoq)
        when :empty
          @state[opt].send("#{who}=", :no)
          log.debug("(#{@pstack.conn.object_id}) Telnet negotiation: agreed to disable option #{opt}")
        when :opposite
          @state[opt].send("#{who}=", :no)
          @state[opt].send("#{whoq}=", :empty)
        end
      end
    end
  end

  def handle_zmp(cmd,args)
    log.debug("(#{@pstack.conn.object_id}) ZMP command recieved - '#{cmd}' args: #{args.inspect}" )
    case cmd
    when "zmp.ping"
      @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
        "zmp.time#{NUL.chr}#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")}#{NUL.chr}" +
        "#{IAC.chr}#{SE.chr}")
    when "zmp.time"
    when "zmp.ident"
      # That's nice
    when "zmp.check"
      case args[0]
      when /zmp.*/
      # We support all 'zmp.' package and commands so..
        @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
          "zmp.support#{NUL.chr}#{args[0]}{NUL.chr}" +
          "#{IAC.chr}#{SE.chr}")
      else
        @pstack.conn.sendmsg("#{IAC.chr}#{SB.chr}#{ZMP.chr}" +
          "zmp.no-support#{NUL.chr}#{args[0]}#{NUL.chr}" +
          "#{IAC.chr}#{SE.chr}")
      end
    when "zmp.support"
    when "zmp.no-support"
    when "zmp.input"
      # Now we just simply pass this whole load to the Character.parse
      # WARN: This means there is a possibility of out-of-order processing
      #       of @inbuffer, though extremely unlikely.
      @pstack.conn.publish(args[0])
    end
  end

end