]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/telnetlib.py
dist/mkfile: run binds in subshell
[plan9front.git] / sys / lib / python / telnetlib.py
1 r"""TELNET client class.
2
3 Based on RFC 854: TELNET Protocol Specification, by J. Postel and
4 J. Reynolds
5
6 Example:
7
8 >>> from telnetlib import Telnet
9 >>> tn = Telnet('www.python.org', 79)   # connect to finger port
10 >>> tn.write('guido\r\n')
11 >>> print tn.read_all()
12 Login       Name               TTY         Idle    When    Where
13 guido    Guido van Rossum      pts/2        <Dec  2 11:10> snag.cnri.reston..
14
15 >>>
16
17 Note that read_all() won't read until eof -- it just reads some data
18 -- but it guarantees to read at least one byte unless EOF is hit.
19
20 It is possible to pass a Telnet object to select.select() in order to
21 wait until more data is available.  Note that in this case,
22 read_eager() may return '' even if there was data on the socket,
23 because the protocol negotiation may have eaten the data.  This is why
24 EOFError is needed in some cases to distinguish between "no data" and
25 "connection closed" (since the socket also appears ready for reading
26 when it is closed).
27
28 To do:
29 - option negotiation
30 - timeout should be intrinsic to the connection object instead of an
31   option on one of the read calls only
32
33 """
34
35
36 # Imported modules
37 import sys
38 import socket
39 import select
40
41 __all__ = ["Telnet"]
42
43 # Tunable parameters
44 DEBUGLEVEL = 0
45
46 # Telnet protocol defaults
47 TELNET_PORT = 23
48
49 # Telnet protocol characters (don't change)
50 IAC  = chr(255) # "Interpret As Command"
51 DONT = chr(254)
52 DO   = chr(253)
53 WONT = chr(252)
54 WILL = chr(251)
55 theNULL = chr(0)
56
57 SE  = chr(240)  # Subnegotiation End
58 NOP = chr(241)  # No Operation
59 DM  = chr(242)  # Data Mark
60 BRK = chr(243)  # Break
61 IP  = chr(244)  # Interrupt process
62 AO  = chr(245)  # Abort output
63 AYT = chr(246)  # Are You There
64 EC  = chr(247)  # Erase Character
65 EL  = chr(248)  # Erase Line
66 GA  = chr(249)  # Go Ahead
67 SB =  chr(250)  # Subnegotiation Begin
68
69
70 # Telnet protocol options code (don't change)
71 # These ones all come from arpa/telnet.h
72 BINARY = chr(0) # 8-bit data path
73 ECHO = chr(1) # echo
74 RCP = chr(2) # prepare to reconnect
75 SGA = chr(3) # suppress go ahead
76 NAMS = chr(4) # approximate message size
77 STATUS = chr(5) # give status
78 TM = chr(6) # timing mark
79 RCTE = chr(7) # remote controlled transmission and echo
80 NAOL = chr(8) # negotiate about output line width
81 NAOP = chr(9) # negotiate about output page size
82 NAOCRD = chr(10) # negotiate about CR disposition
83 NAOHTS = chr(11) # negotiate about horizontal tabstops
84 NAOHTD = chr(12) # negotiate about horizontal tab disposition
85 NAOFFD = chr(13) # negotiate about formfeed disposition
86 NAOVTS = chr(14) # negotiate about vertical tab stops
87 NAOVTD = chr(15) # negotiate about vertical tab disposition
88 NAOLFD = chr(16) # negotiate about output LF disposition
89 XASCII = chr(17) # extended ascii character set
90 LOGOUT = chr(18) # force logout
91 BM = chr(19) # byte macro
92 DET = chr(20) # data entry terminal
93 SUPDUP = chr(21) # supdup protocol
94 SUPDUPOUTPUT = chr(22) # supdup output
95 SNDLOC = chr(23) # send location
96 TTYPE = chr(24) # terminal type
97 EOR = chr(25) # end or record
98 TUID = chr(26) # TACACS user identification
99 OUTMRK = chr(27) # output marking
100 TTYLOC = chr(28) # terminal location number
101 VT3270REGIME = chr(29) # 3270 regime
102 X3PAD = chr(30) # X.3 PAD
103 NAWS = chr(31) # window size
104 TSPEED = chr(32) # terminal speed
105 LFLOW = chr(33) # remote flow control
106 LINEMODE = chr(34) # Linemode option
107 XDISPLOC = chr(35) # X Display Location
108 OLD_ENVIRON = chr(36) # Old - Environment variables
109 AUTHENTICATION = chr(37) # Authenticate
110 ENCRYPT = chr(38) # Encryption option
111 NEW_ENVIRON = chr(39) # New - Environment variables
112 # the following ones come from
113 # http://www.iana.org/assignments/telnet-options
114 # Unfortunately, that document does not assign identifiers
115 # to all of them, so we are making them up
116 TN3270E = chr(40) # TN3270E
117 XAUTH = chr(41) # XAUTH
118 CHARSET = chr(42) # CHARSET
119 RSP = chr(43) # Telnet Remote Serial Port
120 COM_PORT_OPTION = chr(44) # Com Port Control Option
121 SUPPRESS_LOCAL_ECHO = chr(45) # Telnet Suppress Local Echo
122 TLS = chr(46) # Telnet Start TLS
123 KERMIT = chr(47) # KERMIT
124 SEND_URL = chr(48) # SEND-URL
125 FORWARD_X = chr(49) # FORWARD_X
126 PRAGMA_LOGON = chr(138) # TELOPT PRAGMA LOGON
127 SSPI_LOGON = chr(139) # TELOPT SSPI LOGON
128 PRAGMA_HEARTBEAT = chr(140) # TELOPT PRAGMA HEARTBEAT
129 EXOPL = chr(255) # Extended-Options-List
130 NOOPT = chr(0)
131
132 class Telnet:
133
134     """Telnet interface class.
135
136     An instance of this class represents a connection to a telnet
137     server.  The instance is initially not connected; the open()
138     method must be used to establish a connection.  Alternatively, the
139     host name and optional port number can be passed to the
140     constructor, too.
141
142     Don't try to reopen an already connected instance.
143
144     This class has many read_*() methods.  Note that some of them
145     raise EOFError when the end of the connection is read, because
146     they can return an empty string for other reasons.  See the
147     individual doc strings.
148
149     read_until(expected, [timeout])
150         Read until the expected string has been seen, or a timeout is
151         hit (default is no timeout); may block.
152
153     read_all()
154         Read all data until EOF; may block.
155
156     read_some()
157         Read at least one byte or EOF; may block.
158
159     read_very_eager()
160         Read all data available already queued or on the socket,
161         without blocking.
162
163     read_eager()
164         Read either data already queued or some data available on the
165         socket, without blocking.
166
167     read_lazy()
168         Read all data in the raw queue (processing it first), without
169         doing any socket I/O.
170
171     read_very_lazy()
172         Reads all data in the cooked queue, without doing any socket
173         I/O.
174
175     read_sb_data()
176         Reads available data between SB ... SE sequence. Don't block.
177
178     set_option_negotiation_callback(callback)
179         Each time a telnet option is read on the input flow, this callback
180         (if set) is called with the following parameters :
181         callback(telnet socket, command, option)
182             option will be chr(0) when there is no option.
183         No other action is done afterwards by telnetlib.
184
185     """
186
187     def __init__(self, host=None, port=0):
188         """Constructor.
189
190         When called without arguments, create an unconnected instance.
191         With a hostname argument, it connects the instance; a port
192         number is optional.
193
194         """
195         self.debuglevel = DEBUGLEVEL
196         self.host = host
197         self.port = port
198         self.sock = None
199         self.rawq = ''
200         self.irawq = 0
201         self.cookedq = ''
202         self.eof = 0
203         self.iacseq = '' # Buffer for IAC sequence.
204         self.sb = 0 # flag for SB and SE sequence.
205         self.sbdataq = ''
206         self.option_callback = None
207         if host is not None:
208             self.open(host, port)
209
210     def open(self, host, port=0):
211         """Connect to a host.
212
213         The optional second argument is the port number, which
214         defaults to the standard telnet port (23).
215
216         Don't try to reopen an already connected instance.
217
218         """
219         self.eof = 0
220         if not port:
221             port = TELNET_PORT
222         self.host = host
223         self.port = port
224         msg = "getaddrinfo returns an empty list"
225         for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
226             af, socktype, proto, canonname, sa = res
227             try:
228                 self.sock = socket.socket(af, socktype, proto)
229                 self.sock.connect(sa)
230             except socket.error, msg:
231                 if self.sock:
232                     self.sock.close()
233                 self.sock = None
234                 continue
235             break
236         if not self.sock:
237             raise socket.error, msg
238
239     def __del__(self):
240         """Destructor -- close the connection."""
241         self.close()
242
243     def msg(self, msg, *args):
244         """Print a debug message, when the debug level is > 0.
245
246         If extra arguments are present, they are substituted in the
247         message using the standard string formatting operator.
248
249         """
250         if self.debuglevel > 0:
251             print 'Telnet(%s,%d):' % (self.host, self.port),
252             if args:
253                 print msg % args
254             else:
255                 print msg
256
257     def set_debuglevel(self, debuglevel):
258         """Set the debug level.
259
260         The higher it is, the more debug output you get (on sys.stdout).
261
262         """
263         self.debuglevel = debuglevel
264
265     def close(self):
266         """Close the connection."""
267         if self.sock:
268             self.sock.close()
269         self.sock = 0
270         self.eof = 1
271         self.iacseq = ''
272         self.sb = 0
273
274     def get_socket(self):
275         """Return the socket object used internally."""
276         return self.sock
277
278     def fileno(self):
279         """Return the fileno() of the socket object used internally."""
280         return self.sock.fileno()
281
282     def write(self, buffer):
283         """Write a string to the socket, doubling any IAC characters.
284
285         Can block if the connection is blocked.  May raise
286         socket.error if the connection is closed.
287
288         """
289         if IAC in buffer:
290             buffer = buffer.replace(IAC, IAC+IAC)
291         self.msg("send %r", buffer)
292         self.sock.sendall(buffer)
293
294     def read_until(self, match, timeout=None):
295         """Read until a given string is encountered or until timeout.
296
297         When no match is found, return whatever is available instead,
298         possibly the empty string.  Raise EOFError if the connection
299         is closed and no cooked data is available.
300
301         """
302         n = len(match)
303         self.process_rawq()
304         i = self.cookedq.find(match)
305         if i >= 0:
306             i = i+n
307             buf = self.cookedq[:i]
308             self.cookedq = self.cookedq[i:]
309             return buf
310         s_reply = ([self], [], [])
311         s_args = s_reply
312         if timeout is not None:
313             s_args = s_args + (timeout,)
314             from time import time
315             time_start = time()
316         while not self.eof and select.select(*s_args) == s_reply:
317             i = max(0, len(self.cookedq)-n)
318             self.fill_rawq()
319             self.process_rawq()
320             i = self.cookedq.find(match, i)
321             if i >= 0:
322                 i = i+n
323                 buf = self.cookedq[:i]
324                 self.cookedq = self.cookedq[i:]
325                 return buf
326             if timeout is not None:
327                 elapsed = time() - time_start
328                 if elapsed >= timeout:
329                     break
330                 s_args = s_reply + (timeout-elapsed,)
331         return self.read_very_lazy()
332
333     def read_all(self):
334         """Read all data until EOF; block until connection closed."""
335         self.process_rawq()
336         while not self.eof:
337             self.fill_rawq()
338             self.process_rawq()
339         buf = self.cookedq
340         self.cookedq = ''
341         return buf
342
343     def read_some(self):
344         """Read at least one byte of cooked data unless EOF is hit.
345
346         Return '' if EOF is hit.  Block if no data is immediately
347         available.
348
349         """
350         self.process_rawq()
351         while not self.cookedq and not self.eof:
352             self.fill_rawq()
353             self.process_rawq()
354         buf = self.cookedq
355         self.cookedq = ''
356         return buf
357
358     def read_very_eager(self):
359         """Read everything that's possible without blocking in I/O (eager).
360
361         Raise EOFError if connection closed and no cooked data
362         available.  Return '' if no cooked data available otherwise.
363         Don't block unless in the midst of an IAC sequence.
364
365         """
366         self.process_rawq()
367         while not self.eof and self.sock_avail():
368             self.fill_rawq()
369             self.process_rawq()
370         return self.read_very_lazy()
371
372     def read_eager(self):
373         """Read readily available data.
374
375         Raise EOFError if connection closed and no cooked data
376         available.  Return '' if no cooked data available otherwise.
377         Don't block unless in the midst of an IAC sequence.
378
379         """
380         self.process_rawq()
381         while not self.cookedq and not self.eof and self.sock_avail():
382             self.fill_rawq()
383             self.process_rawq()
384         return self.read_very_lazy()
385
386     def read_lazy(self):
387         """Process and return data that's already in the queues (lazy).
388
389         Raise EOFError if connection closed and no data available.
390         Return '' if no cooked data available otherwise.  Don't block
391         unless in the midst of an IAC sequence.
392
393         """
394         self.process_rawq()
395         return self.read_very_lazy()
396
397     def read_very_lazy(self):
398         """Return any data available in the cooked queue (very lazy).
399
400         Raise EOFError if connection closed and no data available.
401         Return '' if no cooked data available otherwise.  Don't block.
402
403         """
404         buf = self.cookedq
405         self.cookedq = ''
406         if not buf and self.eof and not self.rawq:
407             raise EOFError, 'telnet connection closed'
408         return buf
409
410     def read_sb_data(self):
411         """Return any data available in the SB ... SE queue.
412
413         Return '' if no SB ... SE available. Should only be called
414         after seeing a SB or SE command. When a new SB command is
415         found, old unread SB data will be discarded. Don't block.
416
417         """
418         buf = self.sbdataq
419         self.sbdataq = ''
420         return buf
421
422     def set_option_negotiation_callback(self, callback):
423         """Provide a callback function called after each receipt of a telnet option."""
424         self.option_callback = callback
425
426     def process_rawq(self):
427         """Transfer from raw queue to cooked queue.
428
429         Set self.eof when connection is closed.  Don't block unless in
430         the midst of an IAC sequence.
431
432         """
433         buf = ['', '']
434         try:
435             while self.rawq:
436                 c = self.rawq_getchar()
437                 if not self.iacseq:
438                     if c == theNULL:
439                         continue
440                     if c == "\021":
441                         continue
442                     if c != IAC:
443                         buf[self.sb] = buf[self.sb] + c
444                         continue
445                     else:
446                         self.iacseq += c
447                 elif len(self.iacseq) == 1:
448                     # 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]'
449                     if c in (DO, DONT, WILL, WONT):
450                         self.iacseq += c
451                         continue
452
453                     self.iacseq = ''
454                     if c == IAC:
455                         buf[self.sb] = buf[self.sb] + c
456                     else:
457                         if c == SB: # SB ... SE start.
458                             self.sb = 1
459                             self.sbdataq = ''
460                         elif c == SE:
461                             self.sb = 0
462                             self.sbdataq = self.sbdataq + buf[1]
463                             buf[1] = ''
464                         if self.option_callback:
465                             # Callback is supposed to look into
466                             # the sbdataq
467                             self.option_callback(self.sock, c, NOOPT)
468                         else:
469                             # We can't offer automatic processing of
470                             # suboptions. Alas, we should not get any
471                             # unless we did a WILL/DO before.
472                             self.msg('IAC %d not recognized' % ord(c))
473                 elif len(self.iacseq) == 2:
474                     cmd = self.iacseq[1]
475                     self.iacseq = ''
476                     opt = c
477                     if cmd in (DO, DONT):
478                         self.msg('IAC %s %d',
479                             cmd == DO and 'DO' or 'DONT', ord(opt))
480                         if self.option_callback:
481                             self.option_callback(self.sock, cmd, opt)
482                         else:
483                             self.sock.sendall(IAC + WONT + opt)
484                     elif cmd in (WILL, WONT):
485                         self.msg('IAC %s %d',
486                             cmd == WILL and 'WILL' or 'WONT', ord(opt))
487                         if self.option_callback:
488                             self.option_callback(self.sock, cmd, opt)
489                         else:
490                             self.sock.sendall(IAC + DONT + opt)
491         except EOFError: # raised by self.rawq_getchar()
492             self.iacseq = '' # Reset on EOF
493             self.sb = 0
494             pass
495         self.cookedq = self.cookedq + buf[0]
496         self.sbdataq = self.sbdataq + buf[1]
497
498     def rawq_getchar(self):
499         """Get next char from raw queue.
500
501         Block if no data is immediately available.  Raise EOFError
502         when connection is closed.
503
504         """
505         if not self.rawq:
506             self.fill_rawq()
507             if self.eof:
508                 raise EOFError
509         c = self.rawq[self.irawq]
510         self.irawq = self.irawq + 1
511         if self.irawq >= len(self.rawq):
512             self.rawq = ''
513             self.irawq = 0
514         return c
515
516     def fill_rawq(self):
517         """Fill raw queue from exactly one recv() system call.
518
519         Block if no data is immediately available.  Set self.eof when
520         connection is closed.
521
522         """
523         if self.irawq >= len(self.rawq):
524             self.rawq = ''
525             self.irawq = 0
526         # The buffer size should be fairly small so as to avoid quadratic
527         # behavior in process_rawq() above
528         buf = self.sock.recv(50)
529         self.msg("recv %r", buf)
530         self.eof = (not buf)
531         self.rawq = self.rawq + buf
532
533     def sock_avail(self):
534         """Test whether data is available on the socket."""
535         return select.select([self], [], [], 0) == ([self], [], [])
536
537     def interact(self):
538         """Interaction function, emulates a very dumb telnet client."""
539         if sys.platform == "win32":
540             self.mt_interact()
541             return
542         while 1:
543             rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
544             if self in rfd:
545                 try:
546                     text = self.read_eager()
547                 except EOFError:
548                     print '*** Connection closed by remote host ***'
549                     break
550                 if text:
551                     sys.stdout.write(text)
552                     sys.stdout.flush()
553             if sys.stdin in rfd:
554                 line = sys.stdin.readline()
555                 if not line:
556                     break
557                 self.write(line)
558
559     def mt_interact(self):
560         """Multithreaded version of interact()."""
561         import thread
562         thread.start_new_thread(self.listener, ())
563         while 1:
564             line = sys.stdin.readline()
565             if not line:
566                 break
567             self.write(line)
568
569     def listener(self):
570         """Helper for mt_interact() -- this executes in the other thread."""
571         while 1:
572             try:
573                 data = self.read_eager()
574             except EOFError:
575                 print '*** Connection closed by remote host ***'
576                 return
577             if data:
578                 sys.stdout.write(data)
579             else:
580                 sys.stdout.flush()
581
582     def expect(self, list, timeout=None):
583         """Read until one from a list of a regular expressions matches.
584
585         The first argument is a list of regular expressions, either
586         compiled (re.RegexObject instances) or uncompiled (strings).
587         The optional second argument is a timeout, in seconds; default
588         is no timeout.
589
590         Return a tuple of three items: the index in the list of the
591         first regular expression that matches; the match object
592         returned; and the text read up till and including the match.
593
594         If EOF is read and no text was read, raise EOFError.
595         Otherwise, when nothing matches, return (-1, None, text) where
596         text is the text received so far (may be the empty string if a
597         timeout happened).
598
599         If a regular expression ends with a greedy match (e.g. '.*')
600         or if more than one expression can match the same input, the
601         results are undeterministic, and may depend on the I/O timing.
602
603         """
604         re = None
605         list = list[:]
606         indices = range(len(list))
607         for i in indices:
608             if not hasattr(list[i], "search"):
609                 if not re: import re
610                 list[i] = re.compile(list[i])
611         if timeout is not None:
612             from time import time
613             time_start = time()
614         while 1:
615             self.process_rawq()
616             for i in indices:
617                 m = list[i].search(self.cookedq)
618                 if m:
619                     e = m.end()
620                     text = self.cookedq[:e]
621                     self.cookedq = self.cookedq[e:]
622                     return (i, m, text)
623             if self.eof:
624                 break
625             if timeout is not None:
626                 elapsed = time() - time_start
627                 if elapsed >= timeout:
628                     break
629                 s_args = ([self.fileno()], [], [], timeout-elapsed)
630                 r, w, x = select.select(*s_args)
631                 if not r:
632                     break
633             self.fill_rawq()
634         text = self.read_very_lazy()
635         if not text and self.eof:
636             raise EOFError
637         return (-1, None, text)
638
639
640 def test():
641     """Test program for telnetlib.
642
643     Usage: python telnetlib.py [-d] ... [host [port]]
644
645     Default host is localhost; default port is 23.
646
647     """
648     debuglevel = 0
649     while sys.argv[1:] and sys.argv[1] == '-d':
650         debuglevel = debuglevel+1
651         del sys.argv[1]
652     host = 'localhost'
653     if sys.argv[1:]:
654         host = sys.argv[1]
655     port = 0
656     if sys.argv[2:]:
657         portstr = sys.argv[2]
658         try:
659             port = int(portstr)
660         except ValueError:
661             port = socket.getservbyname(portstr, 'tcp')
662     tn = Telnet()
663     tn.set_debuglevel(debuglevel)
664     tn.open(host, port)
665     tn.interact()
666     tn.close()
667
668 if __name__ == '__main__':
669     test()