*** /usr/lib/python2.3/telnetlib.py Wed Oct 16 03:45:13 2002 --- telnetlib.py Thu Oct 31 12:03:18 2002 *************** *** 26,32 **** when it is closed). Bugs: ! - may hang when connection is slow in the middle of an IAC sequence To do: - option negotiation --- 26,32 ---- when it is closed). Bugs: ! - may hang when connection is slow in the middle of an IAC sequence (FIXED!) To do: - option negotiation *************** *** 56,61 **** --- 56,63 ---- WONT = chr(252) WILL = chr(251) theNULL = chr(0) + SB = chr(250) + SE = chr(240) # Telnet protocol options code (don't change) # These ones all come from arpa/telnet.h *************** *** 117,122 **** --- 119,125 ---- SSPI_LOGON = chr(139) # TELOPT SSPI LOGON PRAGMA_HEARTBEAT = chr(140) # TELOPT PRAGMA HEARTBEAT EXOPL = chr(255) # Extended-Options-List + NOOPT = chr(0) class Telnet: *************** *** 161,170 **** 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. """ --- 164,177 ---- Reads all data in the cooked queue, without doing any socket I/O. + 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. """ *************** *** 185,190 **** --- 192,200 ---- self.irawq = 0 self.cookedq = '' self.eof = 0 + 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) *************** *** 250,255 **** --- 260,267 ---- self.sock.close() self.sock = 0 self.eof = 1 + self.iacseq = '' + self.sb = 0 def get_socket(self): """Return the socket object used internally.""" *************** *** 379,384 **** --- 391,408 ---- if not buf and self.eof and not self.rawq: raise EOFError, 'telnet connection closed' return buf + + def read_sb_data(self): + """Return any data available in the SB ... SE queue. + + Return '' if no SB ... SE available. Should only be called + after seeing a SB or SE command. When a new SB command is + found, old unread SB data will be discarded. Don't block. + + """ + buf = self.sbdataq + self.sbdataq = '' + return buf def set_option_negotiation_callback(self, callback): """Provide a callback function called after each receipt of a telnet option.""" *************** *** 391,430 **** the midst of an IAC sequence. """ ! buf = '' try: while self.rawq: c = self.rawq_getchar() ! if c == theNULL: ! continue ! if c == "\021": ! continue ! if c != IAC: ! buf = buf + c ! continue ! c = self.rawq_getchar() ! if c == IAC: ! buf = buf + c ! elif c in (DO, DONT): ! opt = self.rawq_getchar() ! 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.sendall(IAC + WONT + opt) ! elif c in (WILL, WONT): ! opt = self.rawq_getchar() ! self.msg('IAC %s %d', ! c == WILL and 'WILL' or 'WONT', ord(opt)) ! if self.option_callback: ! self.option_callback(self.sock, c, opt) else: ! self.sock.sendall(IAC + DONT + opt) ! else: ! self.msg('IAC %d not recognized' % ord(c)) except EOFError: # raised by self.rawq_getchar() pass ! self.cookedq = self.cookedq + buf def rawq_getchar(self): """Get next char from raw queue. --- 415,480 ---- the midst of an IAC sequence. """ ! buf = ['', ''] try: while self.rawq: c = self.rawq_getchar() ! if not self.iacseq: ! if c == theNULL: ! continue ! if c == "\021": ! continue ! if c != IAC: ! buf[self.sb] = buf[self.sb] + c ! continue else: ! self.iacseq += c ! elif len(self.iacseq) == 1: ! 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]' ! if c in (DO, DONT, WILL, WONT): ! self.iacseq += c ! continue ! ! self.iacseq = '' ! if c == IAC: ! buf[self.sb] = buf[self.sb] + c else: ! if c == SB: # SB ... SE start. ! self.sb = 1 ! self.sbdataq = '' ! elif c == SE: ! self.sb = 0 ! self.sbdataq = self.sbdataq + buf[1] ! buf[1] = '' ! if self.option_callback: ! 'Actually need this one.' ! self.option_callback(self.sock, c, NOOPT) ! else: ! 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 pass ! self.cookedq = self.cookedq + buf[0] ! self.sbdataq = self.sbdataq + buf[1] def rawq_getchar(self): """Get next char from raw queue.