]> granicus.if.org Git - python/commitdiff
Patch #416079: fix the debug string output when receiving telnet commands.
authorMartin v. Löwis <martin@v.loewis.de>
Thu, 6 Sep 2001 08:51:38 +0000 (08:51 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Thu, 6 Sep 2001 08:51:38 +0000 (08:51 +0000)
added all the telnet options known to arpa/telnet.h
added all the options registered with IANA as of today
added the possibility for the user to have it's own option negotiation callback

Doc/lib/libtelnetlib.tex
Lib/telnetlib.py

index c772839d2bf563e93565452418d6bbee1b97927b..91695b35e27647a0f8588286c0630ccf025407cd 100644 (file)
@@ -9,7 +9,12 @@
 
 The \module{telnetlib} module provides a \class{Telnet} class that
 implements the Telnet protocol.  See \rfc{854} for details about the
-protocol.
+protocol. In addition, it provides symbolic constants for the protocol
+characters (IAC/DONT/DO/WONT/WILL), and for the telnet options. The
+symbolic names of the telnet options follow the definitions in
+\code{arpa/telnet.h}, with the leading \code{TELOPT_} removed. For
+symbolic names of options which are traditionally not included in
+\code{arpa/telnet.h}, see the module source itself.
 
 
 \begin{classdesc}{Telnet}{\optional{host\optional{, port}}}
@@ -158,6 +163,13 @@ or if more than one expression can match the same input, the
 results are indeterministic, and may depend on the I/O timing.
 \end{methoddesc}
 
+\begin{methoddesc}{set_option_negotiation_callback}{callback}
+Each time a telnet option is read on the input flow, this
+\var{callback} (if set) is called with the following parameters :
+callback(telnet socket, command (DO/DONT/WILL/WONT), option).  No other
+action is done afterwards by telnetlib.
+\end{methoddesc}
+
 
 \subsection{Telnet Example \label{telnet-example}}
 \sectionauthor{Peter Funk}{pf@artcom-gmbh.de}
index 3731be7dee0709294bbde17c981123fda3c949d8..c8ddd972cec58bff678887dd1be4d99a19f19fe0 100644 (file)
@@ -57,6 +57,66 @@ WONT = chr(252)
 WILL = chr(251)
 theNULL = chr(0)
 
+# Telnet protocol options code (don't change)
+# These ones all come from arpa/telnet.h
+BINARY = chr(0) # 8-bit data path
+ECHO = chr(1) # echo
+RCP = chr(2) # prepare to reconnect
+SGA = chr(3) # suppress go ahead
+NAMS = chr(4) # approximate message size
+STATUS = chr(5) # give status
+TM = chr(6) # timing mark
+RCTE = chr(7) # remote controlled transmission and echo
+NAOL = chr(8) # negotiate about output line width
+NAOP = chr(9) # negotiate about output page size
+NAOCRD = chr(10) # negotiate about CR disposition
+NAOHTS = chr(11) # negotiate about horizontal tabstops
+NAOHTD = chr(12) # negotiate about horizontal tab disposition
+NAOFFD = chr(13) # negotiate about formfeed disposition
+NAOVTS = chr(14) # negotiate about vertical tab stops
+NAOVTD = chr(15) # negotiate about vertical tab disposition
+NAOLFD = chr(16) # negotiate about output LF disposition
+XASCII = chr(17) # extended ascii character set
+LOGOUT = chr(18) # force logout
+BM = chr(19) # byte macro
+DET = chr(20) # data entry terminal
+SUPDUP = chr(21) # supdup protocol
+SUPDUPOUTPUT = chr(22) # supdup output
+SNDLOC = chr(23) # send location
+TTYPE = chr(24) # terminal type
+EOR = chr(25) # end or record
+TUID = chr(26) # TACACS user identification
+OUTMRK = chr(27) # output marking
+TTYLOC = chr(28) # terminal location number
+VT3270REGIME = chr(29) # 3270 regime
+X3PAD = chr(30) # X.3 PAD
+NAWS = chr(31) # window size
+TSPEED = chr(32) # terminal speed
+LFLOW = chr(33) # remote flow control
+LINEMODE = chr(34) # Linemode option
+XDISPLOC = chr(35) # X Display Location
+OLD_ENVIRON = chr(36) # Old - Environment variables
+AUTHENTICATION = chr(37) # Authenticate
+ENCRYPT = chr(38) # Encryption option
+NEW_ENVIRON = chr(39) # New - Environment variables
+# the following ones come from
+# http://www.iana.org/assignments/telnet-options
+# Unfortunately, that document does not assign identifiers
+# to all of them, so we are making them up
+TN3270E = chr(40) # TN3270E
+XAUTH = chr(41) # XAUTH
+CHARSET = chr(42) # CHARSET
+RSP = chr(43) # Telnet Remote Serial Port
+COM_PORT_OPTION = chr(44) # Com Port Control Option
+SUPPRESS_LOCAL_ECHO = chr(45) # Telnet Suppress Local Echo
+TLS = chr(46) # Telnet Start TLS
+KERMIT = chr(47) # KERMIT
+SEND_URL = chr(48) # SEND-URL
+FORWARD_X = chr(49) # FORWARD_X
+PRAGMA_LOGON = chr(138) # TELOPT PRAGMA LOGON
+SSPI_LOGON = chr(139) # TELOPT SSPI LOGON
+PRAGMA_HEARTBEAT = chr(140) # TELOPT PRAGMA HEARTBEAT
+EXOPL = chr(255) # Extended-Options-List
 
 class Telnet:
 
@@ -101,6 +161,12 @@ class Telnet:
         Reads all data in the cooked queue, without doing any socket
         I/O.
 
+    set_option_negotiation_callback(callback)
+        Each time a telnet option is read on the input flow, this callback
+        (if set) is called with the following parameters :
+        callback(telnet socket, command (DO/DONT/WILL/WONT), option)
+        No other action is done afterwards by telnetlib.
+
     """
 
     def __init__(self, host=None, port=0):
@@ -119,6 +185,7 @@ class Telnet:
         self.irawq = 0
         self.cookedq = ''
         self.eof = 0
+        self.option_callback = None
         if host:
             self.open(host, port)
 
@@ -312,6 +379,10 @@ class Telnet:
             raise EOFError, 'telnet connection closed'
         return buf
 
+    def set_option_negotiation_callback(self, callback):
+        """Provide a callback function called after each receipt of a telnet option."""
+        self.option_callback = callback
+
     def process_rawq(self):
         """Transfer from raw queue to cooked queue.
 
@@ -335,15 +406,21 @@ class Telnet:
                     buf = buf + c
                 elif c in (DO, DONT):
                     opt = self.rawq_getchar()
-                    self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
-                    self.sock.send(IAC + WONT + opt)
+                    self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(opt))
+                    if self.option_callback:
+                        self.option_callback(self.sock, c, opt)
+                    else:
+                        self.sock.send(IAC + WONT + opt)
                 elif c in (WILL, WONT):
                     opt = self.rawq_getchar()
                     self.msg('IAC %s %d',
-                             c == WILL and 'WILL' or 'WONT', ord(c))
-                    self.sock.send(IAC + DONT + opt)
+                             c == WILL and 'WILL' or 'WONT', ord(opt))
+                    if self.option_callback:
+                        self.option_callback(self.sock, c, opt)
+                    else:
+                        self.sock.send(IAC + DONT + opt)
                 else:
-                    self.msg('IAC %s not recognized' % `c`)
+                    self.msg('IAC %d not recognized' % ord(opt))
         except EOFError: # raised by self.rawq_getchar()
             pass
         self.cookedq = self.cookedq + buf