October 30, 2025, 12:54:45 AM

News:

IWBasic runs in Windows 11!


Check what client it is being used

Started by JoaoAfonso, February 01, 2008, 04:15:55 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

JoaoAfonso

Hail.

I have one difficult question someone may have an answer: I am doing a program where persons can connect to it via a socket. After connecting, they type commands and receive feedback. My problem is: if someone connects by a telnet window, each typed character is sent to the program (thats how telnet works); if someone connects using other client, info is just sent after ENTER key is pressed (chr$(13)).
If I want to receive correcly what is sent by telnet, I must use a routine like
IF receivedbytes<>chr$(13) THEN commandline=commandline+ReceivedBytes
if the client is another one, then I must use something like this:
IF instr(receivedbytes,chr$(13)<>0 THEN commandline=left$(receivedbytes,instr(receivedbytes,chr$(13)))

Is there a way to figure out what client is connecting to my program? Do anyone see another solution to this?

Thanks in advance.
JoÃÆ'ƒÂÃ,£o Afonso
Viriato
-----------------
Iberia MUD
www.iberiamud.com
iberiamud.com:5900

JoaoAfonso

It was long ago I posted this and without answer, but now I have more information to talk about.

My doubt first, and as the subject explains, was to know which kind of client someone was using when connecting to my program. The next step would be, and that stills one of my problems already stated in other posts, identify each EOL marks. In a public MUD forum in a similar thread, someone posted it's own code to deal with inputs coming from any client (windows clients, linux clients, pda clients, whatever).
I obviously do not expect someone translate this piece of code from C to EB, but I would like to ask how to make "usable" in EB some parts of it. Btw, this was posted at Mud Connector forum.

#
# 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[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[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[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[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[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[0]
          when WILL
            replies_him(opt[0],true)
          when WONT
            replies_him(opt[0],false)
          when DO
            requests_us(opt[0],true)
          when DONT
            requests_us(opt[0],false)
          end
          # Update interesting things in ProtocolStack after negotiation
          case opt[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[0],data)
          set_mode(:normal)
        else
          log.debug("(#{@pstack.conn.object_id}) Unknown Telnet command - #{b[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[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[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[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


- when checking clients, there are some options which I believe it may be important to my code, but which I do not understand: ECHO, SGA, BINARY, ZMP, EOREC
- nulls, line feeds, new lines, backspaces, deletes, etc - is using chr$(something) better than \n, \r, \0, etc?
- what variations where covered here when Jon Lambert used LF and CR (CRNUL?)?
- what is IAC, AYT, AO, IP, GA, NOP, BRK, DM, EC, EL, DO, DONT, WILL, WONT???
- when he talks about terminals, vt100, vt999, ansi, etc, I admit the more important is to receive the "useful" info from each terminal (the info when someone starts typing until it is typed EOL, excluding this mark). Am I right?

- a last question is, how to send to clients a small phrase with color using telnet protocols? Like "Hello world" with world in red?

I believe this can be a challenge for many of you, but would take much time to answer with much detail :) Anyway, any tips and suggestions will make me improve for sure.

Thank you in advance.
JoÃÆ'ƒÂÃ,£o Afonso
Viriato
-----------------
Iberia MUD
www.iberiamud.com
iberiamud.com:5900

hugh

As to the other commands , i am not sure off,
But the ECHO command can be either "ON" or "OF",
This is a command in a BATCH FILE *.bat
IE,
ECHO on = display to the console,
ECHO off = do not display to the console.

and that is all i know about the "ECHO" command

Hope this little snip helps you

Regards

Hugh

aurelCB

I think that comand BRK is break,maby is much similiar with Aurora code
Uh this C?

JoaoAfonso

Reading the first line, I believe I figure out it is C...
Well, echoing, for my project and my intention at the moment, does not worry me. But that BRK, which prolly means break, what is the conversion to EB? If I need to check in a client input a break, how would be the correct spell? I am after something like

instr(client_input,BRK)

Of course this wont work, but what is the translation to EB? The rest, how the file works, it is easily understandable, also because the file has comments.
JoÃÆ'ƒÂÃ,£o Afonso
Viriato
-----------------
Iberia MUD
www.iberiamud.com
iberiamud.com:5900

pistol350

Regards,

Peter B.

JoaoAfonso

\n
\r
\n\r
\r\n
\0
0x00

As far as I got, CR is \r and LF is \n. Null is \0. 0x00 is null in binary.
Are there more EOL signatures?
JoÃÆ'ƒÂÃ,£o Afonso
Viriato
-----------------
Iberia MUD
www.iberiamud.com
iberiamud.com:5900

Locodarwin