Adding TTYPE support (allows server to query client for information such as name and capabilities, assuming the client supports ttype).

This commit is contained in:
Griatch 2011-11-19 19:34:00 +01:00
parent 3337c0f787
commit 2104fd391b
6 changed files with 135 additions and 11 deletions

View file

@ -158,7 +158,7 @@ class Evennia(object):
"""
Outputs server startup info to the terminal.
"""
print _(' %(servername)s Portal (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION}
print _(' %(servername)s Server (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION}
print ' amp (Portal): %s' % AMP_PORT
def set_restart_mode(self, mode=None):

View file

@ -35,8 +35,8 @@ class Session(object):
# names of attributes that should be affected by syncing.
_attrs_to_sync = ['protocol_key', 'address', 'suid', 'sessid', 'uid', 'uname',
'logged_in', 'cid', 'encoding',
'conn_time', 'cmd_last', 'cmd_last_visible', 'cmd_total']
'conn_time', 'cmd_last', 'cmd_last_visible', 'cmd_total', 'protocol_flags']
def init_session(self, protocol_key, address, sessionhandler):
"""
Initialize the Session. This should be called by the protocol when
@ -71,6 +71,8 @@ class Session(object):
self.cmd_last = self.conn_time
self.cmd_total = 0
self.protocol_flags = {}
# a back-reference to the relevant sessionhandler this
# session is stored in.
self.sessionhandler = sessionhandler

View file

@ -7,17 +7,17 @@ sessions etc.
"""
from twisted.conch.telnet import StatefulTelnetProtocol
from twisted.conch.telnet import Telnet, StatefulTelnetProtocol, IAC, LINEMODE
from src.server.session import Session
from src.server import ttype
from src.utils import utils, ansi
class TelnetProtocol(StatefulTelnetProtocol, Session):
class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
"""
Each player connecting over telnet (ie using most traditional mud
clients) gets a telnet protocol instance assigned to them. All
communication between game and player goes through here.
"""
"""
def connectionMade(self):
"""
This is called when the connection is first
@ -26,9 +26,20 @@ class TelnetProtocol(StatefulTelnetProtocol, Session):
# initialize the session
client_address = self.transport.client
self.init_session("telnet", client_address, self.factory.sessionhandler)
# setup ttype
self.ttype = ttype.Ttype(self)
# add us to sessionhandler
self.sessionhandler.connect(self)
def enableRemote(self, option):
"""
This sets up the options we allow for this protocol.
"""
return (option == LINEMODE or
option == ttype.TTYPE)
def connectionLost(self, reason):
"""
This is executed when the connection is lost for
@ -37,14 +48,34 @@ class TelnetProtocol(StatefulTelnetProtocol, Session):
"""
self.sessionhandler.disconnect(self)
self.transport.loseConnection()
def dataReceived(self, data):
"""
This method will split the incoming data depending on if it
starts with IAC (a telnet command) or not. All other data will
be handled in line mode.
"""
# print "dataRcv:", data,
# try:
# for b in data:
# print ord(b),
# if b == chr(24): print "ttype found!"
# print ""
# except Exception, e:
# print str(e) + ":", str(data)
if data and data[0] == IAC:
super(TelnetProtocol, self).dataReceived(data)
else:
StatefulTelnetProtocol.dataReceived(self, data)
def lineReceived(self, string):
"""
Telnet method called when data is coming in over the telnet
connection. We pass it on to the game engine directly.
"""
self.sessionhandler.data_in(self, string)
# Session hooks
def disconnect(self, reason=None):

91
src/server/ttype.py Normal file
View file

@ -0,0 +1,91 @@
"""
This module implements the TTYPE telnet protocol as per
http://tintin.sourceforge.net/mtts/. It allows the server to ask the
client about its capabilities. If the client also supports TTYPE, it
will return with information such as its name, if it supports colour
etc. If the client does not support TTYPE, this will be ignored.
All data will be stored on the protocol's protocol_flags dictionary,
under the 'TTYPE' key.
"""
# telnet option codes
TTYPE = chr(24)
IS = chr(0)
SEND = chr(1)
# terminal capabilities and their codes
MTTS = [(128,'PROXY'),
(64, 'SCREEN READER'),
(32, 'OSC COLOR PALETTE'),
(16, 'MOUSE TRACKING'),
(8, '256 COLORS'),
(4, 'UTF-8'),
(2, 'VT100'),
(1, 'ANSI')]
class Ttype(object):
"""
Handles ttype negotiations. Called and initiated by the
telnet protocol.
"""
def __init__(self, protocol):
"""
initialize ttype by storing protocol on ourselves and calling
the client to see if it supporst ttype.
the ttype_step indicates how far in the data retrieval we've
gotten.
"""
self.ttype_step = 0
self.protocol = protocol
self.protocol.protocol_flags['TTYPE'] = {}
# setup protocol to handle ttype initialization and negotiation
self.protocol.negotiationMap[TTYPE] = self.negotiate_ttype
# ask if client will ttype, connect callback if it does.
self.protocol.will(TTYPE).addCallbacks(self.negotiate_ttype, self.no_ttype)
def no_ttype(self, option):
"""
Callback if ttype is not supported by client.
"""
pass
def negotiate_ttype(self, option):
"""
Handles negotiation of the ttype protocol once the
client has confirmed that it supports 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.
"""
self.ttype_step += 1
if self.ttype_step == 1:
# set up info storage and initialize subnegotiation
self.protocol.requestNegotiation(TTYPE, SEND)
else:
# receive data
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 and option.startswith('MTTS'):
option = int(option.strip('MTTS '))
self.protocol.protocol_flags['TTYPE']['MTTS'] = option
for codenum, standard in MTTS:
if option == 0:
break
status = option % codenum < option
self.protocol.protocol_flags['TTYPE'][standard] = status
if status:
option = option % codenum
#print "ttype results:", self.protocol.protocol_flags['TTYPE']

View file

@ -404,6 +404,7 @@ def create_player(name, email, password,
email = "dummy@dummy.com"
if user:
new_user = user
email = user.email
else:
if is_superuser:
new_user = User.objects.create_superuser(name, email, password)
@ -423,7 +424,6 @@ def create_player(name, email, password,
if player_dbobj:
new_db_player = player_dbobj
else:
# create new database object
new_db_player = PlayerDB(db_key=name, user=new_user)
new_db_player.save()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 KiB

After

Width:  |  Height:  |  Size: 678 KiB

Before After
Before After