~divmod-dev/divmod.org/no-addperson-2190

« back to all changes in this revision

Viewing changes to Imaginary/pottery/wiring/textserver.py

  • Committer: exarkun
  • Date: 2006-02-26 02:37:39 UTC
  • Revision ID: svn-v4:866e43f7-fbfc-0310-8f2a-ec88d1da2979:trunk:4991
Merge move-pottery-to-trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
import sys, string
 
3
 
 
4
from twisted.conch.insults import insults
 
5
from twisted.python import log, util
 
6
from twisted import copyright as tcopyright
 
7
 
 
8
from pottery import copyright as pcopyright
 
9
from pottery import epottery, resources
 
10
 
 
11
class TextServer(insults.TerminalProtocol):
 
12
    state = 'USERNAME'
 
13
 
 
14
    width = 80
 
15
    height = 24
 
16
 
 
17
    player = None
 
18
    logout = None
 
19
 
 
20
    motd = file(util.sibpath(resources.__file__, 'motd')).read() % {
 
21
        'pythonVersion': sys.version,
 
22
        'twistedVersion': tcopyright.version,
 
23
        'potteryVersion': pcopyright.version}
 
24
 
 
25
    def statefulDispatch(self, prefix, *a, **kw):
 
26
        oldState = self.state
 
27
        newState = getattr(self, prefix + oldState)(*a, **kw)
 
28
        if newState is not None:
 
29
            if self.state == oldState:
 
30
                self.state = newState
 
31
            else:
 
32
                log.msg("Warning: state changed and new state returned")
 
33
 
 
34
    # ITerminalProtocol
 
35
    def terminalSize(self, width, height):
 
36
        self.width = width
 
37
        self.height = height
 
38
 
 
39
        print 'now', self.width, self.height
 
40
 
 
41
        if self.state == 'COMMAND':
 
42
            self._prepareDisplay()
 
43
 
 
44
    def connectionMade(self):
 
45
        self.write(self.motd + '\n')
 
46
        self.write('Username: ')
 
47
        self.lineBuffer = []
 
48
        self.commandHistory = ['']
 
49
        self.historyPosition = None
 
50
 
 
51
    def _prepareDisplay(self):
 
52
        self.terminal.reset()
 
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)
 
58
        self._clearInput()
 
59
 
 
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()
 
66
        else:
 
67
            self.terminal.write(ch)
 
68
 
 
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()
 
75
        else:
 
76
            self.terminal.write('\b \b')
 
77
 
 
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()
 
84
        else:
 
85
            self.write('\n')
 
86
 
 
87
    def keystrokeReceived(self, keyID, modifier):
 
88
        if keyID == '\r' or keyID == '\n':
 
89
            self._clearInput()
 
90
            line = ''.join(self.lineBuffer)
 
91
            self.lineBuffer = []
 
92
            self.lineReceived(line)
 
93
        elif keyID == self.terminal.BACKSPACE or keyID == '\b':
 
94
            if self.lineBuffer:
 
95
                self.lineBuffer.pop()
 
96
                if self._echo:
 
97
                    self._eraseOneInputCharacter()
 
98
        elif keyID in list(string.printable):
 
99
            if self._echo:
 
100
                self._echoInput(keyID)
 
101
            self.lineBuffer.append(keyID)
 
102
        else:
 
103
            print 'Wacky unhandled stuff:', repr(keyID), modifier
 
104
 
 
105
    def connectionLost(self, reason):
 
106
        insults.TerminalProtocol.connectionLost(self, reason)
 
107
        if self.player is not None:
 
108
            self.player.disconnect()
 
109
            self.player = None
 
110
        if self.logout is not None:
 
111
            self.logout()
 
112
            self.logout = None
 
113
 
 
114
 
 
115
    # Other stuff
 
116
    _echo = True
 
117
    def echoOn(self):
 
118
        self._echo = True
 
119
 
 
120
    def echoOff(self):
 
121
        self._echo = False
 
122
 
 
123
    def write(self, bytes):
 
124
        self.terminal.write(bytes)
 
125
 
 
126
    def lineReceived(self, line):
 
127
        self.statefulDispatch('line_', line)
 
128
 
 
129
    def line_IGNORE(self, line):
 
130
        self.write("Your input %r was ignored.\n" % (line,))
 
131
 
 
132
    def line_USERNAME(self, username):
 
133
        self.username = username
 
134
        self.echoOff()
 
135
        self.write('Password: ')
 
136
        return 'PASSWORD'
 
137
 
 
138
    def line_PASSWORD(self, password):
 
139
        username = self.username
 
140
        del self.username
 
141
        self.echoOn()
 
142
        self.write('\n')
 
143
        self.factory.login(username, password
 
144
            ).addCallback(self._cbLogin
 
145
            ).addErrback(self._ebBadPassword
 
146
            ).addErrback(self._ebNoSuchUser, username
 
147
            ).addErrback(log.err
 
148
            )
 
149
        return 'IGNORE'
 
150
 
 
151
    def _cbLogin(self, (iface, avatar, logout)):
 
152
        self.player = avatar
 
153
        self.logout = logout
 
154
        self.player.setProtocol(self)
 
155
        self.state = 'COMMAND'
 
156
 
 
157
        self._prepareDisplay()
 
158
 
 
159
    def _ebBadPassword(self, failure):
 
160
        failure.trap(epottery.BadPassword)
 
161
        self.write('Bad password\nUsername: ')
 
162
        self.state = 'USERNAME'
 
163
 
 
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'
 
169
 
 
170
    def line_MAYBE_CREATE(self, line):
 
171
        if line.lower() in ('y', 'yes'):
 
172
            self.echoOff()
 
173
            self.write('Enter a new password: ')
 
174
            return 'NEW_PASSWORD'
 
175
        else:
 
176
            self.write('Username: ')
 
177
            return 'USERNAME'
 
178
 
 
179
    def line_NEW_PASSWORD(self, password):
 
180
        username = self.username
 
181
        del self.username
 
182
        self.echoOn()
 
183
        self.player = self.factory.create(username, password)
 
184
        self.player.setProtocol(self)
 
185
        return 'COMMAND'
 
186
 
 
187
    def line_COMMAND(self, line):
 
188
        from pottery import wiring
 
189
        wiring.parse(self.terminal, self.player, line)
 
190
        self.commandHistory.append(line)