Files
rubbs/lib/bbs/telnet.rb
2026-05-11 20:24:40 +02:00

136 lines
2.4 KiB
Ruby

# frozen_string_literal: true
module BBS
module Telnet
IAC = 255
WILL = 251
WONT = 252
DO = 253
DONT = 254
SB = 250
SE = 240
ECHO_OPT = 1
SGA_OPT = 3
def negotiate
send_raw [IAC, WILL, SGA_OPT].pack('C*')
send_raw [IAC, WILL, ECHO_OPT].pack('C*')
send_raw [IAC, DO, SGA_OPT].pack('C*')
end
def readkey
loop do
raw = @client.read(1)
return nil if raw.nil?
byte = raw.ord
if byte == IAC
absorb_iac
next
end
case byte
when 13, 10 then return :enter
when 27 then return read_escape_sequence
when 8, 127 then return :backspace
when 3 then return :interrupt
when 32..126 then return raw
end
end
end
def readline
line = +""
last_cr = false
loop do
raw = @client.read(1)
return nil if raw.nil?
byte = raw.ord
if byte == IAC
absorb_iac
last_cr = false
next
end
if byte == 13
last_cr = true
next
end
if byte == 10 || (byte == 0 && last_cr)
write "\r\n"
return line
end
last_cr = false
next if byte == 0
if byte == 8 || byte == 127
unless line.empty?
line.chop!
write "\b \b"
end
next
end
next if byte < 32
line << raw
write raw
end
end
def write(data)
@client.write(data)
rescue StandardError
nil
end
private
def read_escape_sequence
b1 = @client.read(1)
return :escape if b1.nil? || b1 != '['
b2 = @client.read(1)
return :escape if b2.nil?
case b2
when 'A' then :up
when 'B' then :down
when 'C' then :right
when 'D' then :left
else :escape
end
end
def absorb_iac
cmd = @client.read(1)
return if cmd.nil?
case cmd.ord
when SB
loop do
b = @client.read(1)
break if b.nil?
if b.ord == IAC
s = @client.read(1)
break if s.nil? || s.ord == SE
end
end
when WILL, WONT, DO, DONT
@client.read(1)
end
end
def send_raw(data)
@client.write(data)
rescue StandardError
nil
end
end
end