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.
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.
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
I think that comand BRK is break,maby is much similiar with Aurora code
Uh this C?
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.
I don't think this is C synthax.
\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?
The posted code was written in Ruby.
http://www.ruby-lang.org/en/
-S