Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: third_party/twisted_8_1/twisted/conch/telnet.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.conch.test.test_telnet -*-
2 # Copyright (c) 2001-2007 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Telnet protocol implementation.
7
8 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>}
9 """
10
11 import struct
12
13 from zope.interface import implements
14
15 from twisted.internet import protocol, interfaces as iinternet, defer
16 from twisted.python import log
17
18 MODE = chr(1)
19 EDIT = 1
20 TRAPSIG = 2
21 MODE_ACK = 4
22 SOFT_TAB = 8
23 LIT_ECHO = 16
24
25 # Characters gleaned from the various (and conflicting) RFCs. Not all of these are correct.
26
27 NULL = chr(0) # No operation.
28 BEL = chr(7) # Produces an audible or
29 # visible signal (which does
30 # NOT move the print head).
31 BS = chr(8) # Moves the print head one
32 # character position towards
33 # the left margin.
34 HT = chr(9) # Moves the printer to the
35 # next horizontal tab stop.
36 # It remains unspecified how
37 # either party determines or
38 # establishes where such tab
39 # stops are located.
40 LF = chr(10) # Moves the printer to the
41 # next print line, keeping the
42 # same horizontal position.
43 VT = chr(11) # Moves the printer to the
44 # next vertical tab stop. It
45 # remains unspecified how
46 # either party determines or
47 # establishes where such tab
48 # stops are located.
49 FF = chr(12) # Moves the printer to the top
50 # of the next page, keeping
51 # the same horizontal position.
52 CR = chr(13) # Moves the printer to the left
53 # margin of the current line.
54
55 ECHO = chr(1) # User-to-Server: Asks the server to send
56 # Echos of the transmitted data.
57 SGA = chr(3) # Suppress Go Ahead. Go Ahead is silly
58 # and most modern servers should suppress
59 # it.
60 NAWS = chr(31) # Negotiate About Window Size. Indicate that
61 # information about the size of the terminal
62 # can be communicated.
63 LINEMODE = chr(34) # Allow line buffering to be
64 # negotiated about.
65
66 SE = chr(240) # End of subnegotiation parameters.
67 NOP = chr(241) # No operation.
68 DM = chr(242) # "Data Mark": The data stream portion
69 # of a Synch. This should always be
70 # accompanied by a TCP Urgent
71 # notification.
72 BRK = chr(243) # NVT character Break.
73 IP = chr(244) # The function Interrupt Process.
74 AO = chr(245) # The function Abort Output
75 AYT = chr(246) # The function Are You There.
76 EC = chr(247) # The function Erase Character.
77 EL = chr(248) # The function Erase Line
78 GA = chr(249) # The Go Ahead signal.
79 SB = chr(250) # Indicates that what follows is
80 # subnegotiation of the indicated
81 # option.
82 WILL = chr(251) # Indicates the desire to begin
83 # performing, or confirmation that
84 # you are now performing, the
85 # indicated option.
86 WONT = chr(252) # Indicates the refusal to perform,
87 # or continue performing, the
88 # indicated option.
89 DO = chr(253) # Indicates the request that the
90 # other party perform, or
91 # confirmation that you are expecting
92 # the other party to perform, the
93 # indicated option.
94 DONT = chr(254) # Indicates the demand that the
95 # other party stop performing,
96 # or confirmation that you are no
97 # longer expecting the other party
98 # to perform, the indicated option.
99 IAC = chr(255) # Data Byte 255. Introduces a
100 # telnet command.
101
102 LINEMODE_MODE = chr(1)
103 LINEMODE_EDIT = chr(1)
104 LINEMODE_TRAPSIG = chr(2)
105 LINEMODE_MODE_ACK = chr(4)
106 LINEMODE_SOFT_TAB = chr(8)
107 LINEMODE_LIT_ECHO = chr(16)
108 LINEMODE_FORWARDMASK = chr(2)
109 LINEMODE_SLC = chr(3)
110 LINEMODE_SLC_SYNCH = chr(1)
111 LINEMODE_SLC_BRK = chr(2)
112 LINEMODE_SLC_IP = chr(3)
113 LINEMODE_SLC_AO = chr(4)
114 LINEMODE_SLC_AYT = chr(5)
115 LINEMODE_SLC_EOR = chr(6)
116 LINEMODE_SLC_ABORT = chr(7)
117 LINEMODE_SLC_EOF = chr(8)
118 LINEMODE_SLC_SUSP = chr(9)
119 LINEMODE_SLC_EC = chr(10)
120 LINEMODE_SLC_EL = chr(11)
121
122 LINEMODE_SLC_EW = chr(12)
123 LINEMODE_SLC_RP = chr(13)
124 LINEMODE_SLC_LNEXT = chr(14)
125 LINEMODE_SLC_XON = chr(15)
126 LINEMODE_SLC_XOFF = chr(16)
127 LINEMODE_SLC_FORW1 = chr(17)
128 LINEMODE_SLC_FORW2 = chr(18)
129 LINEMODE_SLC_MCL = chr(19)
130 LINEMODE_SLC_MCR = chr(20)
131 LINEMODE_SLC_MCWL = chr(21)
132 LINEMODE_SLC_MCWR = chr(22)
133 LINEMODE_SLC_MCBOL = chr(23)
134 LINEMODE_SLC_MCEOL = chr(24)
135 LINEMODE_SLC_INSRT = chr(25)
136 LINEMODE_SLC_OVER = chr(26)
137 LINEMODE_SLC_ECR = chr(27)
138 LINEMODE_SLC_EWR = chr(28)
139 LINEMODE_SLC_EBOL = chr(29)
140 LINEMODE_SLC_EEOL = chr(30)
141
142 LINEMODE_SLC_DEFAULT = chr(3)
143 LINEMODE_SLC_VALUE = chr(2)
144 LINEMODE_SLC_CANTCHANGE = chr(1)
145 LINEMODE_SLC_NOSUPPORT = chr(0)
146 LINEMODE_SLC_LEVELBITS = chr(3)
147
148 LINEMODE_SLC_ACK = chr(128)
149 LINEMODE_SLC_FLUSHIN = chr(64)
150 LINEMODE_SLC_FLUSHOUT = chr(32)
151 LINEMODE_EOF = chr(236)
152 LINEMODE_SUSP = chr(237)
153 LINEMODE_ABORT = chr(238)
154
155 class ITelnetProtocol(iinternet.IProtocol):
156 def unhandledCommand(command, argument):
157 """A command was received but not understood.
158 """
159
160 def unhandledSubnegotiation(bytes):
161 """A subnegotiation command was received but not understood.
162 """
163
164 def enableLocal(option):
165 """Enable the given option locally.
166
167 This should enable the given option on this side of the
168 telnet connection and return True. If False is returned,
169 the option will be treated as still disabled and the peer
170 will be notified.
171 """
172
173 def enableRemote(option):
174 """Indicate whether the peer should be allowed to enable this option.
175
176 Returns True if the peer should be allowed to enable this option,
177 False otherwise.
178 """
179
180 def disableLocal(option):
181 """Disable the given option locally.
182
183 Unlike enableLocal, this method cannot fail. The option must be
184 disabled.
185 """
186
187 def disableRemote(option):
188 """Indicate that the peer has disabled this option.
189 """
190
191 class ITelnetTransport(iinternet.ITransport):
192 def do(option):
193 """Indicate a desire for the peer to begin performing the given option.
194
195 Returns a Deferred that fires with True when the peer begins performing
196 the option, or False when the peer refuses to perform it. If the peer
197 is already performing the given option, the Deferred will fail with
198 L{AlreadyEnabled}. If a negotiation regarding this option is already
199 in progress, the Deferred will fail with L{AlreadyNegotiating}.
200
201 Note: It is currently possible that this Deferred will never fire,
202 if the peer never responds, or if the peer believes the option to
203 already be enabled.
204 """
205
206 def dont(option):
207 """Indicate a desire for the peer to cease performing the given option.
208
209 Returns a Deferred that fires with True when the peer ceases performing
210 the option. If the peer is not performing the given option, the
211 Deferred will fail with L{AlreadyDisabled}. If negotiation regarding
212 this option is already in progress, the Deferred will fail with
213 L{AlreadyNegotiating}.
214
215 Note: It is currently possible that this Deferred will never fire,
216 if the peer never responds, or if the peer believes the option to
217 already be disabled.
218 """
219
220 def will(option):
221 """Indicate our willingness to begin performing this option locally.
222
223 Returns a Deferred that fires with True when the peer agrees to allow
224 us to begin performing this option, or False if the peer refuses to
225 allow us to begin performing it. If the option is already enabled
226 locally, the Deferred will fail with L{AlreadyEnabled}. If negotiation
227 regarding this option is already in progress, the Deferred will fail wit h
228 L{AlreadyNegotiating}.
229
230 Note: It is currently possible that this Deferred will never fire,
231 if the peer never responds, or if the peer believes the option to
232 already be enabled.
233 """
234
235 def wont(option):
236 """Indicate that we will stop performing the given option.
237
238 Returns a Deferred that fires with True when the peer acknowledges
239 we have stopped performing this option. If the option is already
240 disabled locally, the Deferred will fail with L{AlreadyDisabled}.
241 If negotiation regarding this option is already in progress,
242 the Deferred will fail with L{AlreadyNegotiating}.
243
244 Note: It is currently possible that this Deferred will never fire,
245 if the peer never responds, or if the peer believes the option to
246 already be disabled.
247 """
248
249 def requestNegotiation(about, bytes):
250 """Send a subnegotiation request.
251
252 @param about: A byte indicating the feature being negotiated.
253 @param bytes: Any number of bytes containing specific information
254 about the negotiation being requested. No values in this string
255 need to be escaped, as this function will escape any value which
256 requires it.
257 """
258
259 class TelnetError(Exception):
260 pass
261
262 class NegotiationError(TelnetError):
263 def __str__(self):
264 return self.__class__.__module__ + '.' + self.__class__.__name__ + ':' + repr(self.args[0])
265
266 class OptionRefused(NegotiationError):
267 pass
268
269 class AlreadyEnabled(NegotiationError):
270 pass
271
272 class AlreadyDisabled(NegotiationError):
273 pass
274
275 class AlreadyNegotiating(NegotiationError):
276 pass
277
278 class TelnetProtocol(protocol.Protocol):
279 implements(ITelnetProtocol)
280
281 def unhandledCommand(self, command, argument):
282 pass
283
284 def unhandledSubnegotiation(self, command, bytes):
285 pass
286
287 def enableLocal(self, option):
288 pass
289
290 def enableRemote(self, option):
291 pass
292
293 def disableLocal(self, option):
294 pass
295
296 def disableRemote(self, option):
297 pass
298
299
300 class Telnet(protocol.Protocol):
301 """
302 @ivar commandMap: A mapping of bytes to callables. When a
303 telnet command is received, the command byte (the first byte
304 after IAC) is looked up in this dictionary. If a callable is
305 found, it is invoked with the argument of the command, or None
306 if the command takes no argument. Values should be added to
307 this dictionary if commands wish to be handled. By default,
308 only WILL, WONT, DO, and DONT are handled. These should not
309 be overridden, as this class handles them correctly and
310 provides an API for interacting with them.
311
312 @ivar negotiationMap: A mapping of bytes to callables. When
313 a subnegotiation command is received, the command byte (the
314 first byte after SB) is looked up in this dictionary. If
315 a callable is found, it is invoked with the argument of the
316 subnegotiation. Values should be added to this dictionary if
317 subnegotiations are to be handled. By default, no values are
318 handled.
319
320 @ivar options: A mapping of option bytes to their current
321 state. This state is likely of little use to user code.
322 Changes should not be made to it.
323
324 @ivar state: A string indicating the current parse state. It
325 can take on the values "data", "escaped", "command", "newline",
326 "subnegotiation", and "subnegotiation-escaped". Changes
327 should not be made to it.
328
329 @ivar transport: This protocol's transport object.
330 """
331
332 # One of a lot of things
333 state = 'data'
334
335 def __init__(self):
336 self.options = {}
337 self.negotiationMap = {}
338 self.commandMap = {
339 WILL: self.telnet_WILL,
340 WONT: self.telnet_WONT,
341 DO: self.telnet_DO,
342 DONT: self.telnet_DONT}
343
344 def _write(self, bytes):
345 self.transport.write(bytes)
346
347 class _OptionState:
348 class _Perspective:
349 state = 'no'
350 negotiating = False
351 onResult = None
352
353 def __str__(self):
354 return self.state + ('*' * self.negotiating)
355
356 def __init__(self):
357 self.us = self._Perspective()
358 self.him = self._Perspective()
359
360 def __repr__(self):
361 return '<_OptionState us=%s him=%s>' % (self.us, self.him)
362
363 def getOptionState(self, opt):
364 return self.options.setdefault(opt, self._OptionState())
365
366 def _do(self, option):
367 self._write(IAC + DO + option)
368
369 def _dont(self, option):
370 self._write(IAC + DONT + option)
371
372 def _will(self, option):
373 self._write(IAC + WILL + option)
374
375 def _wont(self, option):
376 self._write(IAC + WONT + option)
377
378 def will(self, option):
379 """Indicate our willingness to enable an option.
380 """
381 s = self.getOptionState(option)
382 if s.us.negotiating or s.him.negotiating:
383 return defer.fail(AlreadyNegotiating(option))
384 elif s.us.state == 'yes':
385 return defer.fail(AlreadyEnabled(option))
386 else:
387 s.us.negotiating = True
388 s.us.onResult = d = defer.Deferred()
389 self._will(option)
390 return d
391
392 def wont(self, option):
393 """Indicate we are not willing to enable an option.
394 """
395 s = self.getOptionState(option)
396 if s.us.negotiating or s.him.negotiating:
397 return defer.fail(AlreadyNegotiating(option))
398 elif s.us.state == 'no':
399 return defer.fail(AlreadyDisabled(option))
400 else:
401 s.us.negotiating = True
402 s.us.onResult = d = defer.Deferred()
403 self._wont(option)
404 return d
405
406 def do(self, option):
407 s = self.getOptionState(option)
408 if s.us.negotiating or s.him.negotiating:
409 return defer.fail(AlreadyNegotiating(option))
410 elif s.him.state == 'yes':
411 return defer.fail(AlreadyEnabled(option))
412 else:
413 s.him.negotiating = True
414 s.him.onResult = d = defer.Deferred()
415 self._do(option)
416 return d
417
418 def dont(self, option):
419 s = self.getOptionState(option)
420 if s.us.negotiating or s.him.negotiating:
421 return defer.fail(AlreadyNegotiating(option))
422 elif s.him.state == 'no':
423 return defer.fail(AlreadyDisabled(option))
424 else:
425 s.him.negotiating = True
426 s.him.onResult = d = defer.Deferred()
427 self._dont(option)
428 return d
429
430 def requestNegotiation(self, about, bytes):
431 bytes = bytes.replace(IAC, IAC * 2)
432 self._write(IAC + SB + bytes + IAC + SE)
433
434 def dataReceived(self, data):
435 appDataBuffer = []
436
437 for b in data:
438 if self.state == 'data':
439 if b == IAC:
440 self.state = 'escaped'
441 elif b == '\r':
442 self.state = 'newline'
443 else:
444 appDataBuffer.append(b)
445 elif self.state == 'escaped':
446 if b == IAC:
447 appDataBuffer.append(b)
448 self.state = 'data'
449 elif b == SB:
450 self.state = 'subnegotiation'
451 self.commands = []
452 elif b in (NOP, DM, BRK, IP, AO, AYT, EC, EL, GA):
453 self.state = 'data'
454 if appDataBuffer:
455 self.applicationDataReceived(''.join(appDataBuffer))
456 del appDataBuffer[:]
457 self.commandReceived(b, None)
458 elif b in (WILL, WONT, DO, DONT):
459 self.state = 'command'
460 self.command = b
461 else:
462 raise ValueError("Stumped", b)
463 elif self.state == 'command':
464 self.state = 'data'
465 command = self.command
466 del self.command
467 if appDataBuffer:
468 self.applicationDataReceived(''.join(appDataBuffer))
469 del appDataBuffer[:]
470 self.commandReceived(command, b)
471 elif self.state == 'newline':
472 if b == '\n':
473 appDataBuffer.append('\n')
474 elif b == '\0':
475 appDataBuffer.append('\r')
476 else:
477 appDataBuffer.append('\r' + b)
478 self.state = 'data'
479 elif self.state == 'subnegotiation':
480 if b == IAC:
481 self.state = 'subnegotiation-escaped'
482 else:
483 self.commands.append(b)
484 elif self.state == 'subnegotiation-escaped':
485 if b == SE:
486 self.state = 'data'
487 commands = self.commands
488 del self.commands
489 if appDataBuffer:
490 self.applicationDataReceived(''.join(appDataBuffer))
491 del appDataBuffer[:]
492 self.negotiate(commands)
493 else:
494 self.state = 'subnegotiation'
495 self.commands.append(b)
496 else:
497 raise ValueError("How'd you do this?")
498
499 if appDataBuffer:
500 self.applicationDataReceived(''.join(appDataBuffer))
501
502
503 def connectionLost(self, reason):
504 for state in self.options.values():
505 if state.us.onResult is not None:
506 d = state.us.onResult
507 state.us.onResult = None
508 d.errback(reason)
509 if state.him.onResult is not None:
510 d = state.him.onResult
511 state.him.onResult = None
512 d.errback(reason)
513
514 def applicationDataReceived(self, bytes):
515 """Called with application-level data.
516 """
517
518 def unhandledCommand(self, command, argument):
519 """Called for commands for which no handler is installed.
520 """
521
522 def commandReceived(self, command, argument):
523 cmdFunc = self.commandMap.get(command)
524 if cmdFunc is None:
525 self.unhandledCommand(command, argument)
526 else:
527 cmdFunc(argument)
528
529 def unhandledSubnegotiation(self, command, bytes):
530 """Called for subnegotiations for which no handler is installed.
531 """
532
533 def negotiate(self, bytes):
534 command, bytes = bytes[0], bytes[1:]
535 cmdFunc = self.negotiationMap.get(command)
536 if cmdFunc is None:
537 self.unhandledSubnegotiation(command, bytes)
538 else:
539 cmdFunc(bytes)
540
541 def telnet_WILL(self, option):
542 s = self.getOptionState(option)
543 self.willMap[s.him.state, s.him.negotiating](self, s, option)
544
545 def will_no_false(self, state, option):
546 # He is unilaterally offering to enable an option.
547 if self.enableRemote(option):
548 state.him.state = 'yes'
549 self._do(option)
550 else:
551 self._dont(option)
552
553 def will_no_true(self, state, option):
554 # Peer agreed to enable an option in response to our request.
555 state.him.state = 'yes'
556 state.him.negotiating = False
557 d = state.him.onResult
558 state.him.onResult = None
559 d.callback(True)
560 assert self.enableRemote(option), "enableRemote must return True in this context (for option %r)" % (option,)
561
562 def will_yes_false(self, state, option):
563 # He is unilaterally offering to enable an already-enabled option.
564 # Ignore this.
565 pass
566
567 def will_yes_true(self, state, option):
568 # This is a bogus state. It is here for completeness. It will
569 # never be entered.
570 assert False, "will_yes_true can never be entered, but was called with % r, %r" % (state, option)
571
572 willMap = {('no', False): will_no_false, ('no', True): will_no_true,
573 ('yes', False): will_yes_false, ('yes', True): will_yes_true}
574
575 def telnet_WONT(self, option):
576 s = self.getOptionState(option)
577 self.wontMap[s.him.state, s.him.negotiating](self, s, option)
578
579 def wont_no_false(self, state, option):
580 # He is unilaterally demanding that an already-disabled option be/remain disabled.
581 # Ignore this (although we could record it and refuse subsequent enable attempts
582 # from our side - he can always refuse them again though, so we won't)
583 pass
584
585 def wont_no_true(self, state, option):
586 # Peer refused to enable an option in response to our request.
587 state.him.negotiating = False
588 d = state.him.onResult
589 state.him.onResult = None
590 d.errback(OptionRefused(option))
591
592 def wont_yes_false(self, state, option):
593 # Peer is unilaterally demanding that an option be disabled.
594 state.him.state = 'no'
595 self.disableRemote(option)
596 self._dont(option)
597
598 def wont_yes_true(self, state, option):
599 # Peer agreed to disable an option at our request.
600 state.him.state = 'no'
601 state.him.negotiating = False
602 d = state.him.onResult
603 state.him.onResult = None
604 d.callback(True)
605 self.disableRemote(option)
606
607 wontMap = {('no', False): wont_no_false, ('no', True): wont_no_true,
608 ('yes', False): wont_yes_false, ('yes', True): wont_yes_true}
609
610 def telnet_DO(self, option):
611 s = self.getOptionState(option)
612 self.doMap[s.us.state, s.us.negotiating](self, s, option)
613
614 def do_no_false(self, state, option):
615 # Peer is unilaterally requesting that we enable an option.
616 if self.enableLocal(option):
617 state.us.state = 'yes'
618 self._will(option)
619 else:
620 self._wont(option)
621
622 def do_no_true(self, state, option):
623 # Peer agreed to allow us to enable an option at our request.
624 state.us.state = 'yes'
625 state.us.negotiating = False
626 d = state.us.onResult
627 state.us.onResult = None
628 d.callback(True)
629 self.enableLocal(option)
630
631 def do_yes_false(self, state, option):
632 # Peer is unilaterally requesting us to enable an already-enabled option .
633 # Ignore this.
634 pass
635
636 def do_yes_true(self, state, option):
637 # This is a bogus state. It is here for completeness. It will never be
638 # entered.
639 assert False, "do_yes_true can never be entered, but was called with %r, %r" % (state, option)
640
641 doMap = {('no', False): do_no_false, ('no', True): do_no_true,
642 ('yes', False): do_yes_false, ('yes', True): do_yes_true}
643
644 def telnet_DONT(self, option):
645 s = self.getOptionState(option)
646 self.dontMap[s.us.state, s.us.negotiating](self, s, option)
647
648 def dont_no_false(self, state, option):
649 # Peer is unilaterally demanding us to disable an already-disabled optio n.
650 # Ignore this.
651 pass
652
653 def dont_no_true(self, state, option):
654 # This is a bogus state. It is here for completeness. It will never be
655 # entered.
656 assert False, "dont_no_true can never be entered, but was called with %r , %r" % (state, option)
657
658
659 def dont_yes_false(self, state, option):
660 # Peer is unilaterally demanding we disable an option.
661 state.us.state = 'no'
662 self.disableLocal(option)
663 self._wont(option)
664
665 def dont_yes_true(self, state, option):
666 # Peer acknowledged our notice that we will disable an option.
667 state.us.state = 'no'
668 state.us.negotiating = False
669 d = state.us.onResult
670 state.us.onResult = None
671 d.callback(True)
672 self.disableLocal(option)
673
674 dontMap = {('no', False): dont_no_false, ('no', True): dont_no_true,
675 ('yes', False): dont_yes_false, ('yes', True): dont_yes_true}
676
677 def enableLocal(self, option):
678 """
679 Reject all attempts to enable options.
680 """
681 return False
682
683
684 def enableRemote(self, option):
685 """
686 Reject all attempts to enable options.
687 """
688 return False
689
690
691 def disableLocal(self, option):
692 """
693 Signal a programming error by raising an exception.
694
695 L{enableLocal} must return true for the given value of C{option} in
696 order for this method to be called. If a subclass of L{Telnet}
697 overrides enableLocal to allow certain options to be enabled, it must
698 also override disableLocal to disable those options.
699
700 @raise NotImplementedError: Always raised.
701 """
702 raise NotImplementedError(
703 "Don't know how to disable local telnet option %r" % (option,))
704
705
706 def disableRemote(self, option):
707 """
708 Signal a programming error by raising an exception.
709
710 L{enableRemote} must return true for the given value of C{option} in
711 order for this method to be called. If a subclass of L{Telnet}
712 overrides enableRemote to allow certain options to be enabled, it must
713 also override disableRemote tto disable those options.
714
715 @raise NotImplementedError: Always raised.
716 """
717 raise NotImplementedError(
718 "Don't know how to disable remote telnet option %r" % (option,))
719
720
721
722 class ProtocolTransportMixin:
723 def write(self, bytes):
724 self.transport.write(bytes.replace('\n', '\r\n'))
725
726 def writeSequence(self, seq):
727 self.transport.writeSequence(seq)
728
729 def loseConnection(self):
730 self.transport.loseConnection()
731
732 def getHost(self):
733 return self.transport.getHost()
734
735 def getPeer(self):
736 return self.transport.getPeer()
737
738 class TelnetTransport(Telnet, ProtocolTransportMixin):
739 """
740 @ivar protocol: An instance of the protocol to which this
741 transport is connected, or None before the connection is
742 established and after it is lost.
743
744 @ivar protocolFactory: A callable which returns protocol instances
745 which provide L{ITelnetProtocol}. This will be invoked when a
746 connection is established. It is passed *protocolArgs and
747 **protocolKwArgs.
748
749 @ivar protocolArgs: A tuple of additional arguments to
750 pass to protocolFactory.
751
752 @ivar protocolKwArgs: A dictionary of additional arguments
753 to pass to protocolFactory.
754 """
755
756 disconnecting = False
757
758 protocolFactory = None
759 protocol = None
760
761 def __init__(self, protocolFactory=None, *a, **kw):
762 Telnet.__init__(self)
763 if protocolFactory is not None:
764 self.protocolFactory = protocolFactory
765 self.protocolArgs = a
766 self.protocolKwArgs = kw
767
768 def connectionMade(self):
769 if self.protocolFactory is not None:
770 self.protocol = self.protocolFactory(*self.protocolArgs, **self.prot ocolKwArgs)
771 assert ITelnetProtocol.providedBy(self.protocol)
772 try:
773 factory = self.factory
774 except AttributeError:
775 pass
776 else:
777 self.protocol.factory = factory
778 self.protocol.makeConnection(self)
779
780 def connectionLost(self, reason):
781 Telnet.connectionLost(self, reason)
782 if self.protocol is not None:
783 try:
784 self.protocol.connectionLost(reason)
785 finally:
786 del self.protocol
787
788 def enableLocal(self, option):
789 return self.protocol.enableLocal(option)
790
791 def enableRemote(self, option):
792 return self.protocol.enableRemote(option)
793
794 def disableLocal(self, option):
795 return self.protocol.disableLocal(option)
796
797 def disableRemote(self, option):
798 return self.protocol.disableRemote(option)
799
800 def unhandledSubnegotiation(self, command, bytes):
801 self.protocol.unhandledSubnegotiation(command, bytes)
802
803 def unhandledCommand(self, command, argument):
804 self.protocol.unhandledCommand(command, argument)
805
806 def applicationDataReceived(self, bytes):
807 self.protocol.dataReceived(bytes)
808
809 def write(self, data):
810 ProtocolTransportMixin.write(self, data.replace('\xff','\xff\xff'))
811
812
813 class TelnetBootstrapProtocol(TelnetProtocol, ProtocolTransportMixin):
814 implements()
815
816 protocol = None
817
818 def __init__(self, protocolFactory, *args, **kw):
819 self.protocolFactory = protocolFactory
820 self.protocolArgs = args
821 self.protocolKwArgs = kw
822
823 def connectionMade(self):
824 self.transport.negotiationMap[NAWS] = self.telnet_NAWS
825 self.transport.negotiationMap[LINEMODE] = self.telnet_LINEMODE
826
827 for opt in (LINEMODE, NAWS, SGA):
828 self.transport.do(opt).addErrback(log.err)
829 for opt in (ECHO,):
830 self.transport.will(opt).addErrback(log.err)
831
832 self.protocol = self.protocolFactory(*self.protocolArgs, **self.protocol KwArgs)
833
834 try:
835 factory = self.factory
836 except AttributeError:
837 pass
838 else:
839 self.protocol.factory = factory
840
841 self.protocol.makeConnection(self)
842
843 def connectionLost(self, reason):
844 if self.protocol is not None:
845 try:
846 self.protocol.connectionLost(reason)
847 finally:
848 del self.protocol
849
850 def dataReceived(self, data):
851 self.protocol.dataReceived(data)
852
853 def enableLocal(self, opt):
854 if opt == ECHO:
855 return True
856 elif opt == SGA:
857 return True
858 else:
859 return False
860
861 def enableRemote(self, opt):
862 if opt == LINEMODE:
863 self.transport.requestNegotiation(LINEMODE, MODE + chr(TRAPSIG))
864 return True
865 elif opt == NAWS:
866 return True
867 elif opt == SGA:
868 return True
869 else:
870 return False
871
872 def telnet_NAWS(self, bytes):
873 # NAWS is client -> server *only*. self.protocol will
874 # therefore be an ITerminalTransport, the `.protocol'
875 # attribute of which will be an ITerminalProtocol. Maybe.
876 # You know what, XXX TODO clean this up.
877 if len(bytes) == 4:
878 width, height = struct.unpack('!HH', ''.join(bytes))
879 self.protocol.terminalProtocol.terminalSize(width, height)
880 else:
881 log.msg("Wrong number of NAWS bytes")
882
883
884 linemodeSubcommands = {
885 LINEMODE_SLC: 'SLC'}
886 def telnet_LINEMODE(self, bytes):
887 revmap = {}
888 linemodeSubcommand = bytes[0]
889 if 0:
890 # XXX TODO: This should be enabled to parse linemode subnegotiation.
891 getattr(self, 'linemode_' + self.linemodeSubcommands[linemodeSubcomm and])(bytes[1:])
892
893 def linemode_SLC(self, bytes):
894 chunks = zip(*[iter(bytes)]*3)
895 for slcFunction, slcValue, slcWhat in chunks:
896 # Later, we should parse stuff.
897 'SLC', ord(slcFunction), ord(slcValue), ord(slcWhat)
898
899 from twisted.protocols import basic
900
901 class StatefulTelnetProtocol(basic.LineReceiver, TelnetProtocol):
902 delimiter = '\n'
903
904 state = 'Discard'
905
906 def connectionLost(self, reason):
907 basic.LineReceiver.connectionLost(self, reason)
908 TelnetProtocol.connectionLost(self, reason)
909
910 def lineReceived(self, line):
911 oldState = self.state
912 newState = getattr(self, "telnet_" + oldState)(line)
913 if newState is not None:
914 if self.state == oldState:
915 self.state = newState
916 else:
917 log.msg("Warning: state changed and new state returned")
918
919 def telnet_Discard(self, line):
920 pass
921
922 from twisted.cred import credentials
923
924 class AuthenticatingTelnetProtocol(StatefulTelnetProtocol):
925 """A protocol which prompts for credentials and attempts to authenticate the m.
926
927 Username and password prompts are given (the password is obscured). When th e
928 information is collected, it is passed to a portal and an avatar implementin g
929 L{ITelnetProtocol} is requested. If an avatar is returned, it connected to this
930 protocol's transport, and this protocol's transport is connected to it.
931 Otherwise, the user is re-prompted for credentials.
932 """
933
934 state = "User"
935 protocol = None
936
937 def __init__(self, portal):
938 self.portal = portal
939
940 def connectionMade(self):
941 self.transport.write("Username: ")
942
943 def connectionLost(self, reason):
944 StatefulTelnetProtocol.connectionLost(self, reason)
945 if self.protocol is not None:
946 try:
947 self.protocol.connectionLost(reason)
948 self.logout()
949 finally:
950 del self.protocol, self.logout
951
952 def telnet_User(self, line):
953 self.username = line
954 self.transport.will(ECHO)
955 self.transport.write("Password: ")
956 return 'Password'
957
958 def telnet_Password(self, line):
959 username, password = self.username, line
960 del self.username
961 def login(ignored):
962 creds = credentials.UsernamePassword(username, password)
963 d = self.portal.login(creds, None, ITelnetProtocol)
964 d.addCallback(self._cbLogin)
965 d.addErrback(self._ebLogin)
966 self.transport.wont(ECHO).addCallback(login)
967 return 'Discard'
968
969 def _cbLogin(self, ial):
970 interface, protocol, logout = ial
971 assert interface is ITelnetProtocol
972 self.protocol = protocol
973 self.logout = logout
974 self.state = 'Command'
975
976 protocol.makeConnection(self.transport)
977 self.transport.protocol = protocol
978
979 def _ebLogin(self, failure):
980 self.transport.write("\nAuthentication failed\n")
981 self.transport.write("Username: ")
982 self.state = "User"
983
984 __all__ = [
985 # Exceptions
986 'TelnetError', 'NegotiationError', 'OptionRefused',
987 'AlreadyNegotiating', 'AlreadyEnabled', 'AlreadyDisabled',
988
989 # Interfaces
990 'ITelnetProtocol', 'ITelnetTransport',
991
992 # Other stuff, protocols, etc.
993 'Telnet', 'TelnetProtocol', 'TelnetTransport',
994 'TelnetBootstrapProtocol',
995
996 ]
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/conch/tap.py ('k') | third_party/twisted_8_1/twisted/conch/test/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698