mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 01:36:32 +01:00
Implemented better client identification in telnet TTYPE, including a long-standing reversal of DO TTYPE and WILL TTYPE which is due to a typo in the tintin++ TTYPE specification and which was only fixable by going to the original Telnet TTYPE specification from 1989. Should now correctly identify the most common clients that supports e.g. xterm256 colors.
This commit is contained in:
parent
bc8ce9f394
commit
d159f6731d
1 changed files with 78 additions and 53 deletions
|
|
@ -25,17 +25,6 @@ MTTS = [(128, 'PROXY'),
|
|||
(4, 'UTF-8'),
|
||||
(2, 'VT100'),
|
||||
(1, 'ANSI')]
|
||||
# some clients sends erroneous strings instead
|
||||
# of capability numbers. We try to convert back.
|
||||
MTTS_invert = {"PROXY": 128,
|
||||
"SCREEN COLOR PALETTE": 64,
|
||||
"OSC COLOR PALETTE": 32,
|
||||
"MOUSE TRACKING": 16,
|
||||
"256 COLORS": 8,
|
||||
"UTF-8": 4,
|
||||
"VT100": 2,
|
||||
"ANSI": 1}
|
||||
|
||||
|
||||
class Ttype(object):
|
||||
"""
|
||||
|
|
@ -53,65 +42,101 @@ class Ttype(object):
|
|||
self.ttype_step = 0
|
||||
self.protocol = protocol
|
||||
self.protocol.protocol_flags['TTYPE'] = {"init_done": False}
|
||||
# is it a safe bet to assume ANSI is always supported?
|
||||
self.protocol.protocol_flags['TTYPE']['ANSI'] = True
|
||||
# setup protocol to handle ttype initialization and negotiation
|
||||
self.protocol.negotiationMap[TTYPE] = self.do_ttype
|
||||
self.protocol.negotiationMap[TTYPE] = self.will_ttype
|
||||
# ask if client will ttype, connect callback if it does.
|
||||
self.protocol.will(TTYPE).addCallbacks(self.do_ttype, self.no_ttype)
|
||||
self.protocol.do(TTYPE).addCallbacks(self.will_ttype, self.wont_ttype)
|
||||
|
||||
def no_ttype(self, option):
|
||||
def wont_ttype(self, option):
|
||||
"""
|
||||
Callback if ttype is not supported by client.
|
||||
"""
|
||||
self.protocol.protocol_flags['TTYPE'] = {"init_done": True}
|
||||
self.protocol.protocol_flags['TTYPE']["init_done"] = True
|
||||
|
||||
def do_ttype(self, option):
|
||||
def will_ttype(self, option):
|
||||
"""
|
||||
Handles negotiation of the ttype protocol once the
|
||||
client has confirmed that it supports the ttype
|
||||
client has confirmed that it will respond with the ttype
|
||||
protocol.
|
||||
|
||||
The negotiation proceeds in several steps, each returning a
|
||||
certain piece of information about the client. All data is
|
||||
stored on protocol.protocol_flags under the TTYPE key.
|
||||
"""
|
||||
|
||||
options = self.protocol.protocol_flags.get('TTYPE')
|
||||
if options and options.get('init_done'):
|
||||
|
||||
if options and options.get('init_done') or self.ttype_step > 3:
|
||||
return
|
||||
|
||||
self.ttype_step += 1
|
||||
|
||||
if self.ttype_step == 1:
|
||||
# set up info storage and initialize subnegotiation
|
||||
self.protocol.requestNegotiation(TTYPE, SEND)
|
||||
else:
|
||||
# receive data
|
||||
try:
|
||||
option = "".join(option).lstrip(IS)
|
||||
if self.ttype_step == 2:
|
||||
self.protocol.protocol_flags['TTYPE']['CLIENTNAME'] = option
|
||||
self.protocol.requestNegotiation(TTYPE, SEND)
|
||||
elif self.ttype_step == 3:
|
||||
self.protocol.protocol_flags['TTYPE']['TERM'] = option
|
||||
self.protocol.requestNegotiation(TTYPE, SEND)
|
||||
elif self.ttype_step == 4:
|
||||
try:
|
||||
option = int(option.strip('MTTS '))
|
||||
except ValueError:
|
||||
# it seems some clients don't send MTTS according to
|
||||
# protocol specification, but instead just sends
|
||||
# the data as plain strings. We try to convert back.
|
||||
option = MTTS_invert.get(option.strip('MTTS ').upper())
|
||||
if not option:
|
||||
# no conversion possible. Give up.
|
||||
self.protocol.protocol_flags['TTYPE']['init_done'] = True
|
||||
return
|
||||
self.protocol.protocol_flags['TTYPE']['MTTS'] = option
|
||||
for codenum, standard in MTTS:
|
||||
if option == 0:
|
||||
break
|
||||
status = option & codenum
|
||||
self.protocol.protocol_flags['TTYPE'][standard] = status
|
||||
#if status:
|
||||
# option = option % codenum
|
||||
self.protocol.protocol_flags['TTYPE']['init_done'] = True
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
#print "ttype results:", self.protocol.protocol_flags['TTYPE'],id(self.protocol)
|
||||
#print "incoming TTYPE option:", option
|
||||
|
||||
if self.ttype_step == 0:
|
||||
# just start the request chain
|
||||
self.protocol.requestNegotiation(TTYPE, SEND)
|
||||
|
||||
elif self.ttype_step == 1:
|
||||
# this is supposed to be the name of the client/terminal.
|
||||
# For clients not supporting the extended TTYPE
|
||||
# definition, subsequent calls will just repeat-return this.
|
||||
clientname = option.upper()
|
||||
# use name to identify support for xterm256. Many of these
|
||||
# only support after a certain version, but all support
|
||||
# it since at least 4 years. We assume recent client here for now.
|
||||
xterm256 = False
|
||||
if clientname.startswith("MUDLET"):
|
||||
# supports xterm256 stably since 1.1 (2010?)
|
||||
xterm256 = clientname.split("MUDLET",1)[1].strip() >= "1.1"
|
||||
else:
|
||||
xterm256 = (clientname.startswith("XTERM") or
|
||||
clientname.endswith("-256COLOR") or
|
||||
clientname in ("ATLANTIS", # > 0.9.9.0 (aug 2009)
|
||||
"CMUD", # > 3.04 (mar 2009)
|
||||
"KILDCLIENT", # > 2.2.0 (sep 2005)
|
||||
"MUDLET", # > beta 15 (sep 2009)
|
||||
"MUSHCLIENT", # > 4.02 (apr 2007)
|
||||
"PUTTY")) # > 0.58 (apr 2005)
|
||||
|
||||
# all clients supporting TTYPE at all seem to support ANSI
|
||||
self.protocol.protocol_flags['TTYPE']['ANSI'] = True
|
||||
self.protocol.protocol_flags['TTYPE']['256 COLORS'] = xterm256
|
||||
self.protocol.protocol_flags['TTYPE']['CLIENTNAME'] = clientname
|
||||
self.protocol.requestNegotiation(TTYPE, SEND)
|
||||
|
||||
elif self.ttype_step == 2:
|
||||
# this is a term capabilities flag
|
||||
term = option
|
||||
# identify xterm256 based on flag
|
||||
xterm256 = (term.endswith("-256color") # Apple Terminal, old Tintin
|
||||
or term.endswith("xterm") and # old Tintin, Putty
|
||||
not term.endswith("-color"))
|
||||
if xterm256:
|
||||
self.protocol.protocol_flags['TTYPE']['ANSI'] = True
|
||||
self.protocol.protocol_flags['TTYPE']['256 COLORS'] = xterm256
|
||||
self.protocol.protocol_flags['TTYPE']['TERM'] = term
|
||||
# request next information
|
||||
self.protocol.requestNegotiation(TTYPE, SEND)
|
||||
|
||||
elif self.ttype_step == 3:
|
||||
# the MTTS bitstring identifying term capabilities
|
||||
if option.startswith("MTTS"):
|
||||
option = option.split(" ")[1]
|
||||
if option.isdigit():
|
||||
# a number - determine the actual capabilities
|
||||
option = int(option)
|
||||
support = dict((capability, True) for bitval, capability in MTTS if option & bitval > 0)
|
||||
self.protocol.protocol_flags['TTYPE'].update(support)
|
||||
else:
|
||||
# some clients send erroneous MTTS as a string. Add directly.
|
||||
self.protocol.protocol_flags['TTYPE'][option.upper()] = True
|
||||
|
||||
self.protocol.protocol_flags['TTYPE']['init_done'] = True
|
||||
#print "TTYPE final:", self.protocol.protocol_flags['TTYPE']
|
||||
self.ttype_step += 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue