Here’s a very simple, crude, yet easy to understand Python telnet client. I made this because I often need to access some old-fashioned telnet-only services — some eagle BBS services to be precise — at work. Unfortunately, the telnet port is blocked by the company’s firewall, and therefore I have no choice but using a remote UNIX server as a proxy via SSH. The server, however, does not provide the traditional telnet command for the security reasons, so I created this script to circumvent the restriction (the server has Python anyway.. interesting).

Please note that, because of its primary purpose, this script is somewhat geared toward the eagle BBS compromising some usability as a general purpose telnet client although this issue can be cured easily (see the description below). It works with Python 1.5+. OK, let’s look around the source code first (or click here to download). Here we go:

  1. #!/home/bin/python
  2. #
  3. # Synopsis: terminal-based python telnet client
  4. # Usage: ptelnet.py [hostname] [portnumber]
  5. #
  6. # Programmed by Gang Seong Lee
  7. # Revised by Ha Hong (a.k.a. RedRiver)
  8.  
  9. from telnetlib import Telnet
  10. import time, sys
  11. from threading import *
  12. import sys, tty, termios
  13.  
  14. host = 'localhost';
  15. port = 23
  16.  
  17. class ReaderThread(Thread):
  18.         def __init__(self, telnet):
  19.                 self.telnet = telnet
  20.                 Thread.__init__(self)
  21.  
  22.         def run(self):
  23.                 while 1:
  24.                         str = self.telnet.read_some()
  25.                         if str == '': break
  26.                         sys.stdout.write(str)
  27.                         sys.stdout.flush()
  28.  
  29. def main(host, port):
  30.         telnet = Telnet()
  31.         telnet.open(host, port)
  32.  
  33.         reader = ReaderThread(telnet)
  34.         reader.start()
  35.  
  36.         fd = sys.stdin.fileno()
  37.         old_settings = termios.tcgetattr(fd)
  38.         tty.setraw(fd)
  39.  
  40.         while 1:
  41.                 if not reader.isAlive(): break
  42.                 # org: line = raw_input()
  43.                 # org: telnet.write(line+'n')
  44.                 ch = sys.stdin.read(1)
  45.                 telnet.write(ch)
  46.         telnet.close()
  47.         #termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
  48.         termios.tcsetattr(fd, 1, old_settings)
  49.  
  50. if __name__ == '__main__':
  51.         try:
  52.                 host = sys.argv[1]
  53.         except: pass
  54.         try:
  55.                 port = int(sys.argv[2])
  56.         except: pass
  57.         main(host, port)

 

The usage of the command is quite simple:

$ python ptelnet.py [hostname] [port number]

Or, if you give the executable permission with proper path replacement of the first line, this would be like this:

$ ./ptelnet.py [hostname] [port number]

Of course, here’s some humble descriptions matching the humble code: the script is essentially composed of two parts — the reader thread part and key stroke handling part. The reader thread runs in the background and prints whatever received in the telnet session to the standard output. The key stroke handling part sends whatever entered to the telnet session without local echoing. This non-echoing is perfect for eagle BBS services, but if you consider using this script for general telnet servers, you may want to revert the key handling part (line 40–48) to the original one as the followings which echoes locally: (but there is one stupid drawback: it echoes your password.)

  1.         while 1:
  2.                 if not reader.isAlive(): break
  3.                 line = raw_input()
  4.                 telnet.write(line+'n')
  5.         telnet.close()

 

Known issues: the script has some minor problems. First, it does not understand the telnet terminal control handshaking at all. Second, the TERMIOS and stdin.read() thing which is essentially the getch() is not perfectly portable. You may have to mend it especially in order to run under Windows. Third, if the script terminates unexpectedly your terminal could be messed up. Issue the reset command in this case.