(py-indent-right, py-outdent-left): new commands, bound to C-c C-r and
[python/dscho.git] / Demo / cwilib / telnetlib.py
blob3a48a79b75bd5ecbaae0dc3f73b19b2e4befe980
1 # A TELNET client class. Based on RFC 854: TELNET Protocol
2 # Specification, by J. Postel and J. Reynolds
5 # Example:
7 # >>> from telnetlib import Telnet
8 # >>> tn = Telnet('voorn.cwi.nl', 79) # connect to finger port
9 # >>> tn.write('guido\r\n')
10 # >>> print tn.read_all()
11 # Login name: guido In real life: Guido van Rossum
12 # Office: M353, x4127 Home phone: 020-6225521
13 # Directory: /ufs/guido Shell: /usr/local/bin/esh
14 # On since Oct 28 11:02:16 on ttyq1
15 # Project: Multimedia Kernel Systems
16 # No Plan.
17 # >>>
19 # Note that read() won't read until eof -- it just reads some data
20 # (but it guarantees to read at least one byte unless EOF is hit).
22 # It is possible to pass a Telnet object to select.select() in order
23 # to wait until more data is available. Note that in this case,
24 # read_eager() may return '' even if there was data on the socket,
25 # because the protocol negotiation may have eaten the data.
26 # This is why EOFError is needed to distinguish between "no data"
27 # and "connection closed" (since the socket also appears ready for
28 # reading when it is closed).
30 # Bugs:
31 # - may hang when connection is slow in the middle of an IAC sequence
33 # To do:
34 # - option negotiation
37 # Imported modules
38 import socket
39 import select
40 import string
41 import regsub
43 # Tunable parameters
44 DEBUGLEVEL = 0
46 # Telnet protocol defaults
47 TELNET_PORT = 23
49 # Telnet protocol characters (don't change)
50 IAC = chr(255) # "Interpret As Command"
51 DONT = chr(254)
52 DO = chr(253)
53 WONT = chr(252)
54 WILL = chr(251)
57 # Telnet interface class
59 class Telnet:
61 # Constructor
62 def __init__(self, host, *args):
63 if not args:
64 port = TELNET_PORT
65 else:
66 if len(args) > 1: raise TypeError, 'too many args'
67 port = args[0]
68 if not port: port = TELNET_PORT
69 self.debuglevel = DEBUGLEVEL
70 self.host = host
71 self.port = port
72 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
73 self.sock.connect((self.host, self.port))
74 self.rawq = ''
75 self.irawq = 0
76 self.cookedq = ''
77 self.eof = 0
79 # Destructor
80 def __del__(self):
81 self.close()
83 # Debug message
84 def msg(self, msg, *args):
85 if self.debuglevel > 0:
86 print 'Telnet(%s,%d):' % (self.host, self.port), msg % args
88 # Set debug level
89 def set_debuglevel(self, debuglevel):
90 self.debuglevel = debuglevel
92 # Explicit close
93 def close(self):
94 if self.sock:
95 self.sock.close()
96 self.sock = None
97 self.eof = 1
99 # Return socket (e.g. for select)
100 def get_socket(self):
101 return self.sock
103 # Return socket's fileno (e.g. for select)
104 def fileno(self):
105 return self.sock.fileno()
107 # Write a string to the socket, doubling any IAC characters
108 # Might block if the connection is blocked
109 # May raise socket.error if the connection is closed
110 def write(self, buffer):
111 if IAC in buffer:
112 buffer = regsub.gsub(IAC, IAC+IAC, buffer)
113 self.sock.send(buffer)
115 # The following read_* methods exist:
116 # Special case:
117 # - read_until() reads until a string is encountered or a timeout is hit
118 # These may block:
119 # - read_all() reads all data until EOF
120 # - read_some() reads at least one byte until EOF
121 # These may do I/O but won't block doing it:
122 # - read_very_eager() reads all data available on the socket
123 # - read_eager() reads either data already queued or some data
124 # available on the socket
125 # These don't do I/O:
126 # - read_lazy() reads all data in the raw queue (processing it first)
127 # - read_very_lazy() reads all data in the cooked queue
129 # Read until a given string is encountered or until timeout
130 # Raise EOFError if connection closed and no cooked data available
131 # Return '' if no cooked data available otherwise
132 def read_until(self, match, *args):
133 if not args:
134 timeout = None
135 else:
136 if len(args) > 1: raise TypeError, 'too many args'
137 timeout = args[0]
138 n = len(match)
139 self.process_rawq()
140 i = string.find(self.cookedq, match)
141 if i >= 0:
142 i = i+n
143 buf = self.cookedq[:i]
144 self.cookedq = self.cookedq[i:]
145 return buf
146 s_reply = ([self], [], [])
147 s_args = s_reply
148 if timeout is not None:
149 s_args = s_args + (timeout,)
150 while not self.eof and apply(select.select, s_args) == s_reply:
151 i = max(0, len(self.cookedq)-n)
152 self.fill_rawq()
153 self.process_rawq()
154 i = string.find(self.cookedq, match, i)
155 if i >= 0:
156 i = i+n
157 buf = self.cookedq[:i]
158 self.cookedq = self.cookedq[i:]
159 return buf
160 return self.read_very_lazy()
162 # Read all data until EOF
163 # Block until connection closed
164 def read_all(self):
165 self.process_rawq()
166 while not self.eof:
167 self.fill_rawq()
168 self.process_rawq()
169 buf = self.cookedq
170 self.cookedq = ''
171 return buf
173 # Read at least one byte of cooked data unless EOF is hit
174 # Return '' if EOF is hit
175 # Block if no data is immediately available
176 def read_some(self):
177 self.process_rawq()
178 while not self.cookedq and not self.eof:
179 self.fill_rawq()
180 self.process_rawq()
181 buf = self.cookedq
182 self.cookedq = ''
183 return buf
185 # Read everything that's possible without blocking in I/O (eager)
186 # Raise EOFError if connection closed and no cooked data available
187 # Return '' if no cooked data available otherwise
188 # Don't block unless in the midst of an IAC sequence
189 def read_very_eager(self):
190 self.process_rawq()
191 while not self.eof and self.sock_avail():
192 self.fill_rawq()
193 self.process_rawq()
194 return self.read_very_lazy()
196 # Read readily available data
197 # Raise EOFError if connection closed and no cooked data available
198 # Return '' if no cooked data available otherwise
199 # Don't block unless in the midst of an IAC sequence
200 def read_eager(self):
201 self.process_rawq()
202 while not self.cookedq and not self.eof and self.sock_avail():
203 self.fill_rawq()
204 self.process_rawq()
205 return self.read_very_lazy()
207 # Process and return data that's already in the queues (lazy)
208 # Raise EOFError if connection closed and no data available
209 # Return '' if no cooked data available otherwise
210 # Don't block unless in the midst of an IAC sequence
211 def read_lazy(self):
212 self.process_rawq()
213 return self.read_very_lazy()
215 # Return any data available in the cooked queue (very lazy)
216 # Raise EOFError if connection closed and no data available
217 # Return '' if no cooked data available otherwise
218 # Don't block
219 def read_very_lazy(self):
220 buf = self.cookedq
221 self.cookedq = ''
222 if not buf and self.eof and not self.rawq:
223 raise EOFError, 'telnet connection closed'
224 return buf
226 # Transfer from raw queue to cooked queue
227 # Set self.eof when connection is closed
228 # Don't block unless in the midst of an IAC sequence
229 def process_rawq(self):
230 buf = ''
231 try:
232 while self.rawq:
233 c = self.rawq_getchar()
234 if c != IAC:
235 buf = buf + c
236 continue
237 c = self.rawq_getchar()
238 if c == IAC:
239 buf = buf + c
240 elif c in (DO, DONT):
241 opt = self.rawq_getchar()
242 self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
243 self.sock.send(IAC + WONT + opt)
244 elif c in (WILL, WONT):
245 opt = self.rawq_getchar()
246 self.msg('IAC %s %d',
247 c == WILL and 'WILL' or 'WONT', ord(c))
248 else:
249 self.msg('IAC %s not recognized' % `c`)
250 except EOFError: # raised by self.rawq_getchar()
251 pass
252 self.cookedq = self.cookedq + buf
254 # Get next char from raw queue
255 # Block if no data is immediately available
256 # Raise EOFError when connection is closed
257 def rawq_getchar(self):
258 if not self.rawq:
259 self.fill_rawq()
260 if self.eof:
261 raise EOFError
262 c = self.rawq[self.irawq]
263 self.irawq = self.irawq + 1
264 if self.irawq >= len(self.rawq):
265 self.rawq = ''
266 self.irawq = 0
267 return c
269 # Fill raw queue from exactly one recv() system call
270 # Block if no data is immediately available
271 # Set self.eof when connection is closed
272 def fill_rawq(self):
273 if self.irawq >= len(self.rawq):
274 self.rawq = ''
275 self.irawq = 0
276 # The buffer size should be fairly small so as to avoid quadratic
277 # behavior in process_rawq() above
278 buf = self.sock.recv(50)
279 self.eof = (not buf)
280 self.rawq = self.rawq + buf
282 # Test whether data is available on the socket
283 def sock_avail(self):
284 return select.select([self], [], [], 0) == ([self], [], [])
287 # Test program
288 # Usage: test [-d] ... [host [port]]
289 def test():
290 import sys, string, socket, select
291 debuglevel = 0
292 while sys.argv[1:] and sys.argv[1] == '-d':
293 debuglevel = debuglevel+1
294 del sys.argv[1]
295 host = 'localhost'
296 if sys.argv[1:]:
297 host = sys.argv[1]
298 port = 0
299 if sys.argv[2:]:
300 portstr = sys.argv[2]
301 try:
302 port = string.atoi(portstr)
303 except string.atoi_error:
304 port = socket.getservbyname(portstr, 'tcp')
305 tn = Telnet(host, port)
306 tn.set_debuglevel(debuglevel)
307 while 1:
308 rfd, wfd, xfd = select.select([tn, sys.stdin], [], [])
309 if sys.stdin in rfd:
310 line = sys.stdin.readline()
311 tn.write(line)
312 if tn in rfd:
313 try:
314 text = tn.read_eager()
315 except EOFError:
316 print '*** Connection closed by remote host ***'
317 break
318 if text:
319 sys.stdout.write(text)
320 sys.stdout.flush()
321 tn.close()