blob: 5c862e78de80217b2bbcf1d1c4210febf4018065 [file] [log] [blame]
Guido van Rossum74b3f8a1993-10-28 09:53:13 +00001# Telnet client library
2
3import socket
4import select
5import string
6import regsub
7
8# Tunable parameters
9TIMEOUT = 30.0
10DEBUGLEVEL = 1
11
12# Telnet protocol defaults
13TELNET_PORT = 23
14
15# Telnet protocol characters (don't change)
16IAC = chr(255) # "Interpret As Command"
17DONT = chr(254)
18DO = chr(253)
19WONT = chr(252)
20WILL = chr(251)
21
22
23# Telnet interface class
24
25class Telnet:
26
27 # Constructor
28 def __init__(self, host, port):
29 self.debuglevel = DEBUGLEVEL
30 self.host = host
31 if not port: port = TELNET_PORT
32 self.port = port
33 self.timeout = TIMEOUT
34 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35 self.sock.connect((self.host, self.port))
36 self.rawq = ''
37 self.irawq = 0
38 self.cookedq = ''
39
40 # Destructor
41 def __del__(self):
42 self.close()
43
44 # Print debug message
45 def msg(self, msg, *args):
46 if self.debuglevel > 0:
47 print 'TELNET:', msg%args
48
49 # Set debug level
50 def set_debuglevel(self, debuglevel):
51 self.debuglevel = debuglevel
52
53 # Set time-out on certain reads
54 def set_timeout(self, timeout):
55 self.timeout = float(timeout)
56
57 # Explicit close
58 def close(self):
59 if self.sock:
60 self.sock.close()
61 self.sock = None
62
63 # Return socket (e.g. for select)
64 def get_socket(self):
65 return self.sock
66
67 # Return socket's fileno (e.g. for select)
68 def fileno(self):
69 return self.sock.fileno()
70
71 # Write a string to the socket, doubling any IAC characters
72 def write(self, buffer):
73 if IAC in buffer:
74 buffer = regsub.gsub(IAC, IAC+IAC, buffer)
75 self.sock.send(buffer)
76
77 # Read until a given string is encountered or until timeout
78 def read_until(self, match):
79## self.msg('read_until(%s)' % `match`)
80 n = len(match)
81 self.process_rawq()
82 i = string.find(self.cookedq, match)
83 if i < 0:
84 i = max(0, len(self.cookedq)-n)
85 self.fill_cookedq()
86 i = string.find(self.cookedq, match, i)
87 if i >= 0:
88 i = i+n
89 buf = self.cookedq[:i]
90 self.cookedq = self.cookedq[i:]
91## self.msg('read_until(%s) -> %s' % (`match`, `buf`))
92 return buf
93 while select.select([self], [], [], self.timeout) == \
94 ([self], [], []):
95 i = max(0, len(self.cookedq)-n)
96 self.fill_rawq()
97 self.process_rawq()
98 i = string.find(self.cookedq, match, i)
99 if i >= 0:
100 i = i+n
101 buf = self.cookedq[:i]
102 self.cookedq = self.cookedq[i:]
103## self.msg('read_until(%s) -> %s' %
104## (`match`, `buf`))
105 return buf
106 buf = self.cookedq
107 self.cookedq = ''
108## self.msg('read_until(%s) -> %s' % (`match`, `buf`))
109 return buf
110
111 # Read everything that's possible without really blocking
112 def read_now(self):
113 self.fill_cookedq()
114 buf = self.cookedq
115 self.cookedq = ''
116## self.msg('read_now() --> %s' % `buf`)
117 return buf
118
119 # Fill cooked queue without blocking
120 def fill_cookedq(self):
121 self.process_rawq()
122 while select.select([self], [], [], 0) == ([self], [], []):
123 self.fill_rawq()
124 if not self.rawq:
125 raise EOFError
126 self.process_rawq()
127
128 # Transfer from raw queue to cooked queue
129 def process_rawq(self):
130 # There is some silliness going on here in an attempt
131 # to avoid quadratic behavior with large inputs...
132 buf = ''
133 while self.rawq:
134 c = self.rawq_getchar()
135 if c != IAC:
136 buf = buf + c
137 if len(buf) >= 44:
138## self.msg('transfer: %s' % `buf`)
139 self.cookedq = self.cookedq + buf
140 buf = ''
141 continue
142 c = self.rawq_getchar()
143 if c == IAC:
144 buf = buf + c
145 elif c in (DO, DONT):
146 opt = self.rawq_getchar()
147 self.msg('IAC %s %d',
148 c == DO and 'DO' or 'DONT',
149 ord(c))
150 self.sock.send(IAC + WONT + opt)
151 elif c in (WILL, WONT):
152 opt = self.rawq_getchar()
153 self.msg('IAC %s %d',
154 c == WILL and 'WILL' or 'WONT',
155 ord(c))
156 else:
157 self.msg('IAC %s not recognized' % `c`)
158## self.msg('transfer: %s' % `buf`)
159 self.cookedq = self.cookedq + buf
160
161 # Get next char from raw queue, blocking if necessary
162 def rawq_getchar(self):
163 if not self.rawq:
164 self.fill_rawq()
165 if self.irawq >= len(self.rawq):
166 raise EOFError
167 c = self.rawq[self.irawq]
168 self.irawq = self.irawq + 1
169 if self.irawq >= len(self.rawq):
170 self.rawq = ''
171 self.irawq = 0
172 return c
173
174 # Fill raw queue
175 def fill_rawq(self):
176 if self.irawq >= len(self.rawq):
177 self.rawq = ''
178 self.irawq = 0
179 buf = self.sock.recv(50)
180## self.msg('fill_rawq(): %s' % `buf`)
181 self.rawq = self.rawq + buf