Index: dist/src/Doc/lib/libtelnetlib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtelnetlib.tex,v retrieving revision 1.11 diff -c -r1.11 libtelnetlib.tex *** dist/src/Doc/lib/libtelnetlib.tex 4 Nov 2002 17:41:18 -0000 1.11 --- dist/src/Doc/lib/libtelnetlib.tex 7 Jan 2003 21:18:39 -0000 *************** *** 177,187 **** 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} --- 177,189 ---- results are indeterministic, and may depend on the I/O timing. \end{methoddesc} ! \begin{methoddesc}{option_callback}{command, option} ! Called each time a telnet command is read on the input flow. ! \var{option} will be \code{chr(0)} when there is no option. No other action is done afterwards by telnetlib. + + By default, all option negotiation requests are refused. Override this + method to support specific options. \end{methoddesc} *************** *** 211,214 **** --- 213,249 ---- tn.write("exit\n") print tn.read_all() + \end{verbatim} + + An example of subclassing Telnet to handle specific options: + + \begin{verbatim} + from telnetlib import Telnet, IAC, DO, DONT, WILL, WONT, SE + + SGA = chr(3) # suppress go-ahead option, RFC 858 + TTYPE = chr(24) # terminal type option, RFC 1091 + + # Used for TTYPE + SEND = chr(1) + IS = chr(0) + + class TelnetWithOptions(Telnet): + def option_callback(self, cmd, opt): + if cmd == DO and opt == TTYPE: + self.msg('IAC DO TTYPE') + self.msg('send IAC WILL TTYPE') + self.sock.sendall(IAC + WILL + TTYPE) + elif cmd == WILL and opt == SGA: + self.msg('IAC WILL SGA') + self.msg('send IAC DO SGA') + self.sock.sendall(IAC + DO + SGA) + elif cmd == SE: + parms = self.read_sb_data() + self.msg('IAC SB %d %s IAC SE', ord(opt), `parms`) + if opt == TTYPE and parms[0] == SEND: + self.msg('send IAC SB TTYPE IS vt100 IAC SE') + self.sock.sendall(IAC + SB + TTYPE + IS + 'vt100' + IAC + SE) + else: + # Forward everything else to the base class + Telnet.option_callback(self, cmd, opt) \end{verbatim} Index: dist/src/Lib/telnetlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/telnetlib.py,v retrieving revision 1.22 diff -c -r1.22 telnetlib.py *** dist/src/Lib/telnetlib.py 9 Nov 2002 05:08:06 -0000 1.22 --- dist/src/Lib/telnetlib.py 7 Jan 2003 21:18:43 -0000 *************** *** 175,185 **** read_sb_data() Reads available data between SB ... SE sequence. Don't block. ! 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, option) ! option will be chr(0) when there is no option. No other action is done afterwards by telnetlib. """ --- 175,183 ---- read_sb_data() Reads available data between SB ... SE sequence. Don't block. ! option_callback(command, option) ! This method is called each time a telnet command is read on the ! input flow. Option will be chr(0) when there is no option. No other action is done afterwards by telnetlib. """ *************** *** 203,209 **** self.iacseq = '' # Buffer for IAC sequence. self.sb = 0 # flag for SB and SE sequence. self.sbdataq = '' - self.option_callback = None if host is not None: self.open(host, port) --- 201,206 ---- *************** *** 412,421 **** self.sbdataq = '' 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. --- 409,414 ---- *************** *** 454,486 **** self.sb = 0 self.sbdataq = self.sbdataq + buf[1] buf[1] = '' ! if self.option_callback: ! # Callback is supposed to look into ! # the sbdataq ! self.option_callback(self.sock, c, NOOPT) else: ! # We can't offer automatic processing of ! # suboptions. Alas, we should not get any ! # unless we did a WILL/DO before. ! self.msg('IAC %d not recognized' % ord(c)) elif len(self.iacseq) == 2: cmd = self.iacseq[1] self.iacseq = '' opt = c ! if cmd in (DO, DONT): ! self.msg('IAC %s %d', ! cmd == DO and 'DO' or 'DONT', ord(opt)) ! if self.option_callback: ! self.option_callback(self.sock, cmd, opt) ! else: ! self.sock.sendall(IAC + WONT + opt) ! elif cmd in (WILL, WONT): ! self.msg('IAC %s %d', ! cmd == WILL and 'WILL' or 'WONT', ord(opt)) ! if self.option_callback: ! self.option_callback(self.sock, cmd, opt) ! else: ! self.sock.sendall(IAC + DONT + opt) except EOFError: # raised by self.rawq_getchar() self.iacseq = '' # Reset on EOF self.sb = 0 --- 447,462 ---- self.sb = 0 self.sbdataq = self.sbdataq + buf[1] buf[1] = '' ! opt = self.sbdataq[0] ! self.sbdataq = self.sbdataq[1:] ! self.option_callback(c, opt) else: ! self.option_callback(c, NOOPT) elif len(self.iacseq) == 2: cmd = self.iacseq[1] self.iacseq = '' opt = c ! self.option_callback(cmd, opt) except EOFError: # raised by self.rawq_getchar() self.iacseq = '' # Reset on EOF self.sb = 0 *************** *** 522,527 **** --- 498,525 ---- self.msg("recv %s", `buf`) self.eof = (not buf) self.rawq = self.rawq + buf + + def option_callback(self, cmd, opt): + if cmd in (DO, DONT): + self.msg('IAC %s %d', + cmd == DO and 'DO' or 'DONT', ord(opt)) + self.msg('send IAC WONT %d', ord(opt)) + self.sock.sendall(IAC + WONT + opt) + elif cmd in (WILL, WONT): + self.msg('IAC %s %d', + cmd == WILL and 'WILL' or 'WONT', ord(opt)) + self.msg('send IAC DONT %d', ord(opt)) + self.sock.sendall(IAC + DONT + opt) + elif cmd == SB: + # Should never see SB, we only get called after SE arrives + pass + elif cmd == SE: + parms = self.read_sb_data() + self.msg('IAC SB %d %s IAC SE', ord(opt), `parms`) + elif cmd == NOP: + self.msg('IAC NOP') + else: + self.msg('IAC %d not recognized', ord(cmd)) def sock_avail(self): """Test whether data is available on the socket."""