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:
parent
3337c0f787
commit
2104fd391b
6 changed files with 135 additions and 11 deletions
|
|
@ -158,7 +158,7 @@ class Evennia(object):
|
||||||
"""
|
"""
|
||||||
Outputs server startup info to the terminal.
|
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
|
print ' amp (Portal): %s' % AMP_PORT
|
||||||
|
|
||||||
def set_restart_mode(self, mode=None):
|
def set_restart_mode(self, mode=None):
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class Session(object):
|
||||||
# names of attributes that should be affected by syncing.
|
# names of attributes that should be affected by syncing.
|
||||||
_attrs_to_sync = ['protocol_key', 'address', 'suid', 'sessid', 'uid', 'uname',
|
_attrs_to_sync = ['protocol_key', 'address', 'suid', 'sessid', 'uid', 'uname',
|
||||||
'logged_in', 'cid', 'encoding',
|
'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):
|
def init_session(self, protocol_key, address, sessionhandler):
|
||||||
"""
|
"""
|
||||||
|
|
@ -71,6 +71,8 @@ class Session(object):
|
||||||
self.cmd_last = self.conn_time
|
self.cmd_last = self.conn_time
|
||||||
self.cmd_total = 0
|
self.cmd_total = 0
|
||||||
|
|
||||||
|
self.protocol_flags = {}
|
||||||
|
|
||||||
# a back-reference to the relevant sessionhandler this
|
# a back-reference to the relevant sessionhandler this
|
||||||
# session is stored in.
|
# session is stored in.
|
||||||
self.sessionhandler = sessionhandler
|
self.sessionhandler = sessionhandler
|
||||||
|
|
|
||||||
|
|
@ -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.session import Session
|
||||||
|
from src.server import ttype
|
||||||
from src.utils import utils, ansi
|
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
|
Each player connecting over telnet (ie using most traditional mud
|
||||||
clients) gets a telnet protocol instance assigned to them. All
|
clients) gets a telnet protocol instance assigned to them. All
|
||||||
communication between game and player goes through here.
|
communication between game and player goes through here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
"""
|
"""
|
||||||
This is called when the connection is first
|
This is called when the connection is first
|
||||||
|
|
@ -26,9 +26,20 @@ class TelnetProtocol(StatefulTelnetProtocol, Session):
|
||||||
# initialize the session
|
# initialize the session
|
||||||
client_address = self.transport.client
|
client_address = self.transport.client
|
||||||
self.init_session("telnet", client_address, self.factory.sessionhandler)
|
self.init_session("telnet", client_address, self.factory.sessionhandler)
|
||||||
|
|
||||||
|
# setup ttype
|
||||||
|
self.ttype = ttype.Ttype(self)
|
||||||
|
|
||||||
# add us to sessionhandler
|
# add us to sessionhandler
|
||||||
self.sessionhandler.connect(self)
|
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):
|
def connectionLost(self, reason):
|
||||||
"""
|
"""
|
||||||
This is executed when the connection is lost for
|
This is executed when the connection is lost for
|
||||||
|
|
@ -38,6 +49,26 @@ class TelnetProtocol(StatefulTelnetProtocol, Session):
|
||||||
self.sessionhandler.disconnect(self)
|
self.sessionhandler.disconnect(self)
|
||||||
self.transport.loseConnection()
|
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):
|
def lineReceived(self, string):
|
||||||
"""
|
"""
|
||||||
Telnet method called when data is coming in over the telnet
|
Telnet method called when data is coming in over the telnet
|
||||||
|
|
|
||||||
91
src/server/ttype.py
Normal file
91
src/server/ttype.py
Normal 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']
|
||||||
|
|
||||||
|
|
@ -404,6 +404,7 @@ def create_player(name, email, password,
|
||||||
email = "dummy@dummy.com"
|
email = "dummy@dummy.com"
|
||||||
if user:
|
if user:
|
||||||
new_user = user
|
new_user = user
|
||||||
|
email = user.email
|
||||||
else:
|
else:
|
||||||
if is_superuser:
|
if is_superuser:
|
||||||
new_user = User.objects.create_superuser(name, email, password)
|
new_user = User.objects.create_superuser(name, email, password)
|
||||||
|
|
@ -423,7 +424,6 @@ def create_player(name, email, password,
|
||||||
if player_dbobj:
|
if player_dbobj:
|
||||||
new_db_player = player_dbobj
|
new_db_player = player_dbobj
|
||||||
else:
|
else:
|
||||||
# create new database object
|
|
||||||
new_db_player = PlayerDB(db_key=name, user=new_user)
|
new_db_player = PlayerDB(db_key=name, user=new_user)
|
||||||
new_db_player.save()
|
new_db_player.save()
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 672 KiB After Width: | Height: | Size: 678 KiB |
Loading…
Add table
Add a link
Reference in a new issue