4
from twisted.conch.insults import insults
5
from twisted.python import log, util
6
from twisted import copyright as tcopyright
8
from pottery import copyright as pcopyright
9
from pottery import epottery, resources
11
class TextServer(insults.TerminalProtocol):
20
motd = file(util.sibpath(resources.__file__, 'motd')).read() % {
21
'pythonVersion': sys.version,
22
'twistedVersion': tcopyright.version,
23
'potteryVersion': pcopyright.version}
25
def statefulDispatch(self, prefix, *a, **kw):
27
newState = getattr(self, prefix + oldState)(*a, **kw)
28
if newState is not None:
29
if self.state == oldState:
32
log.msg("Warning: state changed and new state returned")
35
def terminalSize(self, width, height):
39
print 'now', self.width, self.height
41
if self.state == 'COMMAND':
42
self._prepareDisplay()
44
def connectionMade(self):
45
self.write(self.motd + '\n')
46
self.write('Username: ')
48
self.commandHistory = ['']
49
self.historyPosition = None
51
def _prepareDisplay(self):
53
self.terminal.eraseDisplay()
54
self.terminal.setScrollRegion(1, self.height - 2)
55
self.terminal.cursorPosition(0, self.height - 2)
56
self.terminal.write('-' * (self.width - 1))
57
self.terminal.cursorPosition(0, 0)
60
def _echoInput(self, ch):
61
if self.state == 'COMMAND':
62
self.terminal.saveCursor()
63
self.terminal.cursorPosition(len(self.lineBuffer), self.height - 1)
64
self.terminal.write(ch)
65
self.terminal.restoreCursor()
67
self.terminal.write(ch)
69
def _eraseOneInputCharacter(self):
70
if self.state == 'COMMAND':
71
self.terminal.saveCursor()
72
self.terminal.cursorPosition(len(self.lineBuffer), self.height - 1)
73
self.terminal.write(' ')
74
self.terminal.restoreCursor()
76
self.terminal.write('\b \b')
78
def _clearInput(self):
79
if self.state == 'COMMAND':
80
self.terminal.saveCursor()
81
self.terminal.cursorPosition(0, self.height)
82
self.terminal.eraseLine()
83
self.terminal.restoreCursor()
87
def keystrokeReceived(self, keyID, modifier):
88
if keyID == '\r' or keyID == '\n':
90
line = ''.join(self.lineBuffer)
92
self.lineReceived(line)
93
elif keyID == self.terminal.BACKSPACE or keyID == '\b':
97
self._eraseOneInputCharacter()
98
elif keyID in list(string.printable):
100
self._echoInput(keyID)
101
self.lineBuffer.append(keyID)
103
print 'Wacky unhandled stuff:', repr(keyID), modifier
105
def connectionLost(self, reason):
106
insults.TerminalProtocol.connectionLost(self, reason)
107
if self.player is not None:
108
self.player.disconnect()
110
if self.logout is not None:
123
def write(self, bytes):
124
self.terminal.write(bytes)
126
def lineReceived(self, line):
127
self.statefulDispatch('line_', line)
129
def line_IGNORE(self, line):
130
self.write("Your input %r was ignored.\n" % (line,))
132
def line_USERNAME(self, username):
133
self.username = username
135
self.write('Password: ')
138
def line_PASSWORD(self, password):
139
username = self.username
143
self.factory.login(username, password
144
).addCallback(self._cbLogin
145
).addErrback(self._ebBadPassword
146
).addErrback(self._ebNoSuchUser, username
151
def _cbLogin(self, (iface, avatar, logout)):
154
self.player.setProtocol(self)
155
self.state = 'COMMAND'
157
self._prepareDisplay()
159
def _ebBadPassword(self, failure):
160
failure.trap(epottery.BadPassword)
161
self.write('Bad password\nUsername: ')
162
self.state = 'USERNAME'
164
def _ebNoSuchUser(self, failure, username):
165
failure.trap(epottery.NoSuchUser)
166
self.username = username
167
self.write("No such user. Create? ")
168
self.state = 'MAYBE_CREATE'
170
def line_MAYBE_CREATE(self, line):
171
if line.lower() in ('y', 'yes'):
173
self.write('Enter a new password: ')
174
return 'NEW_PASSWORD'
176
self.write('Username: ')
179
def line_NEW_PASSWORD(self, password):
180
username = self.username
183
self.player = self.factory.create(username, password)
184
self.player.setProtocol(self)
187
def line_COMMAND(self, line):
188
from pottery import wiring
189
wiring.parse(self.terminal, self.player, line)
190
self.commandHistory.append(line)