Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | """TELNET client class. |
2 | ||
3 | Based on RFC 854: TELNET Protocol Specification, by J. Postel and | |
4 | J. Reynolds | |
5 | ||
6 | Example: | |
7 | ||
8 | >>> from telnetlib import Telnet | |
9 | >>> tn = Telnet('www.python.org', 79) # connect to finger port | |
10 | >>> tn.write('guido\r\n') | |
11 | >>> print tn.read_all() | |
12 | Login Name TTY Idle When Where | |
13 | guido Guido van Rossum pts/2 <Dec 2 11:10> snag.cnri.reston.. | |
14 | ||
15 | >>> | |
16 | ||
17 | Note that read_all() won't read until eof -- it just reads some data | |
18 | -- but it guarantees to read at least one byte unless EOF is hit. | |
19 | ||
20 | It is possible to pass a Telnet object to select.select() in order to | |
21 | wait until more data is available. Note that in this case, | |
22 | read_eager() may return '' even if there was data on the socket, | |
23 | because the protocol negotiation may have eaten the data. This is why | |
24 | EOFError is needed in some cases to distinguish between "no data" and | |
25 | "connection closed" (since the socket also appears ready for reading | |
26 | when it is closed). | |
27 | ||
28 | To do: | |
29 | - option negotiation | |
30 | - timeout should be intrinsic to the connection object instead of an | |
31 | option on one of the read calls only | |
32 | ||
33 | """ | |
34 | ||
35 | ||
36 | # Imported modules | |
37 | import sys | |
38 | import socket | |
39 | import select | |
40 | ||
41 | __all__ = ["Telnet"] | |
42 | ||
43 | # Tunable parameters | |
44 | DEBUGLEVEL = 0 | |
45 | ||
46 | # Telnet protocol defaults | |
47 | TELNET_PORT = 23 | |
48 | ||
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) | |
55 | theNULL = chr(0) | |
56 | ||
57 | SE = chr(240) # Subnegotiation End | |
58 | NOP = chr(241) # No Operation | |
59 | DM = chr(242) # Data Mark | |
60 | BRK = chr(243) # Break | |
61 | IP = chr(244) # Interrupt process | |
62 | AO = chr(245) # Abort output | |
63 | AYT = chr(246) # Are You There | |
64 | EC = chr(247) # Erase Character | |
65 | EL = chr(248) # Erase Line | |
66 | GA = chr(249) # Go Ahead | |
67 | SB = chr(250) # Subnegotiation Begin | |
68 | ||
69 | ||
70 | # Telnet protocol options code (don't change) | |
71 | # These ones all come from arpa/telnet.h | |
72 | BINARY = chr(0) # 8-bit data path | |
73 | ECHO = chr(1) # echo | |
74 | RCP = chr(2) # prepare to reconnect | |
75 | SGA = chr(3) # suppress go ahead | |
76 | NAMS = chr(4) # approximate message size | |
77 | STATUS = chr(5) # give status | |
78 | TM = chr(6) # timing mark | |
79 | RCTE = chr(7) # remote controlled transmission and echo | |
80 | NAOL = chr(8) # negotiate about output line width | |
81 | NAOP = chr(9) # negotiate about output page size | |
82 | NAOCRD = chr(10) # negotiate about CR disposition | |
83 | NAOHTS = chr(11) # negotiate about horizontal tabstops | |
84 | NAOHTD = chr(12) # negotiate about horizontal tab disposition | |
85 | NAOFFD = chr(13) # negotiate about formfeed disposition | |
86 | NAOVTS = chr(14) # negotiate about vertical tab stops | |
87 | NAOVTD = chr(15) # negotiate about vertical tab disposition | |
88 | NAOLFD = chr(16) # negotiate about output LF disposition | |
89 | XASCII = chr(17) # extended ascii character set | |
90 | LOGOUT = chr(18) # force logout | |
91 | BM = chr(19) # byte macro | |
92 | DET = chr(20) # data entry terminal | |
93 | SUPDUP = chr(21) # supdup protocol | |
94 | SUPDUPOUTPUT = chr(22) # supdup output | |
95 | SNDLOC = chr(23) # send location | |
96 | TTYPE = chr(24) # terminal type | |
97 | EOR = chr(25) # end or record | |
98 | TUID = chr(26) # TACACS user identification | |
99 | OUTMRK = chr(27) # output marking | |
100 | TTYLOC = chr(28) # terminal location number | |
101 | VT3270REGIME = chr(29) # 3270 regime | |
102 | X3PAD = chr(30) # X.3 PAD | |
103 | NAWS = chr(31) # window size | |
104 | TSPEED = chr(32) # terminal speed | |
105 | LFLOW = chr(33) # remote flow control | |
106 | LINEMODE = chr(34) # Linemode option | |
107 | XDISPLOC = chr(35) # X Display Location | |
108 | OLD_ENVIRON = chr(36) # Old - Environment variables | |
109 | AUTHENTICATION = chr(37) # Authenticate | |
110 | ENCRYPT = chr(38) # Encryption option | |
111 | NEW_ENVIRON = chr(39) # New - Environment variables | |
112 | # the following ones come from | |
113 | # http://www.iana.org/assignments/telnet-options | |
114 | # Unfortunately, that document does not assign identifiers | |
115 | # to all of them, so we are making them up | |
116 | TN3270E = chr(40) # TN3270E | |
117 | XAUTH = chr(41) # XAUTH | |
118 | CHARSET = chr(42) # CHARSET | |
119 | RSP = chr(43) # Telnet Remote Serial Port | |
120 | COM_PORT_OPTION = chr(44) # Com Port Control Option | |
121 | SUPPRESS_LOCAL_ECHO = chr(45) # Telnet Suppress Local Echo | |
122 | TLS = chr(46) # Telnet Start TLS | |
123 | KERMIT = chr(47) # KERMIT | |
124 | SEND_URL = chr(48) # SEND-URL | |
125 | FORWARD_X = chr(49) # FORWARD_X | |
126 | PRAGMA_LOGON = chr(138) # TELOPT PRAGMA LOGON | |
127 | SSPI_LOGON = chr(139) # TELOPT SSPI LOGON | |
128 | PRAGMA_HEARTBEAT = chr(140) # TELOPT PRAGMA HEARTBEAT | |
129 | EXOPL = chr(255) # Extended-Options-List | |
130 | NOOPT = chr(0) | |
131 | ||
132 | class Telnet: | |
133 | ||
134 | """Telnet interface class. | |
135 | ||
136 | An instance of this class represents a connection to a telnet | |
137 | server. The instance is initially not connected; the open() | |
138 | method must be used to establish a connection. Alternatively, the | |
139 | host name and optional port number can be passed to the | |
140 | constructor, too. | |
141 | ||
142 | Don't try to reopen an already connected instance. | |
143 | ||
144 | This class has many read_*() methods. Note that some of them | |
145 | raise EOFError when the end of the connection is read, because | |
146 | they can return an empty string for other reasons. See the | |
147 | individual doc strings. | |
148 | ||
149 | read_until(expected, [timeout]) | |
150 | Read until the expected string has been seen, or a timeout is | |
151 | hit (default is no timeout); may block. | |
152 | ||
153 | read_all() | |
154 | Read all data until EOF; may block. | |
155 | ||
156 | read_some() | |
157 | Read at least one byte or EOF; may block. | |
158 | ||
159 | read_very_eager() | |
160 | Read all data available already queued or on the socket, | |
161 | without blocking. | |
162 | ||
163 | read_eager() | |
164 | Read either data already queued or some data available on the | |
165 | socket, without blocking. | |
166 | ||
167 | read_lazy() | |
168 | Read all data in the raw queue (processing it first), without | |
169 | doing any socket I/O. | |
170 | ||
171 | read_very_lazy() | |
172 | Reads all data in the cooked queue, without doing any socket | |
173 | I/O. | |
174 | ||
175 | read_sb_data() | |
176 | Reads available data between SB ... SE sequence. Don't block. | |
177 | ||
178 | set_option_negotiation_callback(callback) | |
179 | Each time a telnet option is read on the input flow, this callback | |
180 | (if set) is called with the following parameters : | |
181 | callback(telnet socket, command, option) | |
182 | option will be chr(0) when there is no option. | |
183 | No other action is done afterwards by telnetlib. | |
184 | ||
185 | """ | |
186 | ||
187 | def __init__(self, host=None, port=0): | |
188 | """Constructor. | |
189 | ||
190 | When called without arguments, create an unconnected instance. | |
191 | With a hostname argument, it connects the instance; a port | |
192 | number is optional. | |
193 | ||
194 | """ | |
195 | self.debuglevel = DEBUGLEVEL | |
196 | self.host = host | |
197 | self.port = port | |
198 | self.sock = None | |
199 | self.rawq = '' | |
200 | self.irawq = 0 | |
201 | self.cookedq = '' | |
202 | self.eof = 0 | |
203 | self.iacseq = '' # Buffer for IAC sequence. | |
204 | self.sb = 0 # flag for SB and SE sequence. | |
205 | self.sbdataq = '' | |
206 | self.option_callback = None | |
207 | if host is not None: | |
208 | self.open(host, port) | |
209 | ||
210 | def open(self, host, port=0): | |
211 | """Connect to a host. | |
212 | ||
213 | The optional second argument is the port number, which | |
214 | defaults to the standard telnet port (23). | |
215 | ||
216 | Don't try to reopen an already connected instance. | |
217 | ||
218 | """ | |
219 | self.eof = 0 | |
220 | if not port: | |
221 | port = TELNET_PORT | |
222 | self.host = host | |
223 | self.port = port | |
224 | msg = "getaddrinfo returns an empty list" | |
225 | for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): | |
226 | af, socktype, proto, canonname, sa = res | |
227 | try: | |
228 | self.sock = socket.socket(af, socktype, proto) | |
229 | self.sock.connect(sa) | |
230 | except socket.error, msg: | |
231 | if self.sock: | |
232 | self.sock.close() | |
233 | self.sock = None | |
234 | continue | |
235 | break | |
236 | if not self.sock: | |
237 | raise socket.error, msg | |
238 | ||
239 | def __del__(self): | |
240 | """Destructor -- close the connection.""" | |
241 | self.close() | |
242 | ||
243 | def msg(self, msg, *args): | |
244 | """Print a debug message, when the debug level is > 0. | |
245 | ||
246 | If extra arguments are present, they are substituted in the | |
247 | message using the standard string formatting operator. | |
248 | ||
249 | """ | |
250 | if self.debuglevel > 0: | |
251 | print 'Telnet(%s,%d):' % (self.host, self.port), | |
252 | if args: | |
253 | print msg % args | |
254 | else: | |
255 | print msg | |
256 | ||
257 | def set_debuglevel(self, debuglevel): | |
258 | """Set the debug level. | |
259 | ||
260 | The higher it is, the more debug output you get (on sys.stdout). | |
261 | ||
262 | """ | |
263 | self.debuglevel = debuglevel | |
264 | ||
265 | def close(self): | |
266 | """Close the connection.""" | |
267 | if self.sock: | |
268 | self.sock.close() | |
269 | self.sock = 0 | |
270 | self.eof = 1 | |
271 | self.iacseq = '' | |
272 | self.sb = 0 | |
273 | ||
274 | def get_socket(self): | |
275 | """Return the socket object used internally.""" | |
276 | return self.sock | |
277 | ||
278 | def fileno(self): | |
279 | """Return the fileno() of the socket object used internally.""" | |
280 | return self.sock.fileno() | |
281 | ||
282 | def write(self, buffer): | |
283 | """Write a string to the socket, doubling any IAC characters. | |
284 | ||
285 | Can block if the connection is blocked. May raise | |
286 | socket.error if the connection is closed. | |
287 | ||
288 | """ | |
289 | if IAC in buffer: | |
290 | buffer = buffer.replace(IAC, IAC+IAC) | |
291 | self.msg("send %r", buffer) | |
292 | self.sock.sendall(buffer) | |
293 | ||
294 | def read_until(self, match, timeout=None): | |
295 | """Read until a given string is encountered or until timeout. | |
296 | ||
297 | When no match is found, return whatever is available instead, | |
298 | possibly the empty string. Raise EOFError if the connection | |
299 | is closed and no cooked data is available. | |
300 | ||
301 | """ | |
302 | n = len(match) | |
303 | self.process_rawq() | |
304 | i = self.cookedq.find(match) | |
305 | if i >= 0: | |
306 | i = i+n | |
307 | buf = self.cookedq[:i] | |
308 | self.cookedq = self.cookedq[i:] | |
309 | return buf | |
310 | s_reply = ([self], [], []) | |
311 | s_args = s_reply | |
312 | if timeout is not None: | |
313 | s_args = s_args + (timeout,) | |
314 | while not self.eof and select.select(*s_args) == s_reply: | |
315 | i = max(0, len(self.cookedq)-n) | |
316 | self.fill_rawq() | |
317 | self.process_rawq() | |
318 | i = self.cookedq.find(match, i) | |
319 | if i >= 0: | |
320 | i = i+n | |
321 | buf = self.cookedq[:i] | |
322 | self.cookedq = self.cookedq[i:] | |
323 | return buf | |
324 | return self.read_very_lazy() | |
325 | ||
326 | def read_all(self): | |
327 | """Read all data until EOF; block until connection closed.""" | |
328 | self.process_rawq() | |
329 | while not self.eof: | |
330 | self.fill_rawq() | |
331 | self.process_rawq() | |
332 | buf = self.cookedq | |
333 | self.cookedq = '' | |
334 | return buf | |
335 | ||
336 | def read_some(self): | |
337 | """Read at least one byte of cooked data unless EOF is hit. | |
338 | ||
339 | Return '' if EOF is hit. Block if no data is immediately | |
340 | available. | |
341 | ||
342 | """ | |
343 | self.process_rawq() | |
344 | while not self.cookedq and not self.eof: | |
345 | self.fill_rawq() | |
346 | self.process_rawq() | |
347 | buf = self.cookedq | |
348 | self.cookedq = '' | |
349 | return buf | |
350 | ||
351 | def read_very_eager(self): | |
352 | """Read everything that's possible without blocking in I/O (eager). | |
353 | ||
354 | Raise EOFError if connection closed and no cooked data | |
355 | available. Return '' if no cooked data available otherwise. | |
356 | Don't block unless in the midst of an IAC sequence. | |
357 | ||
358 | """ | |
359 | self.process_rawq() | |
360 | while not self.eof and self.sock_avail(): | |
361 | self.fill_rawq() | |
362 | self.process_rawq() | |
363 | return self.read_very_lazy() | |
364 | ||
365 | def read_eager(self): | |
366 | """Read readily available data. | |
367 | ||
368 | Raise EOFError if connection closed and no cooked data | |
369 | available. Return '' if no cooked data available otherwise. | |
370 | Don't block unless in the midst of an IAC sequence. | |
371 | ||
372 | """ | |
373 | self.process_rawq() | |
374 | while not self.cookedq and not self.eof and self.sock_avail(): | |
375 | self.fill_rawq() | |
376 | self.process_rawq() | |
377 | return self.read_very_lazy() | |
378 | ||
379 | def read_lazy(self): | |
380 | """Process and return data that's already in the queues (lazy). | |
381 | ||
382 | Raise EOFError if connection closed and no data available. | |
383 | Return '' if no cooked data available otherwise. Don't block | |
384 | unless in the midst of an IAC sequence. | |
385 | ||
386 | """ | |
387 | self.process_rawq() | |
388 | return self.read_very_lazy() | |
389 | ||
390 | def read_very_lazy(self): | |
391 | """Return any data available in the cooked queue (very lazy). | |
392 | ||
393 | Raise EOFError if connection closed and no data available. | |
394 | Return '' if no cooked data available otherwise. Don't block. | |
395 | ||
396 | """ | |
397 | buf = self.cookedq | |
398 | self.cookedq = '' | |
399 | if not buf and self.eof and not self.rawq: | |
400 | raise EOFError, 'telnet connection closed' | |
401 | return buf | |
402 | ||
403 | def read_sb_data(self): | |
404 | """Return any data available in the SB ... SE queue. | |
405 | ||
406 | Return '' if no SB ... SE available. Should only be called | |
407 | after seeing a SB or SE command. When a new SB command is | |
408 | found, old unread SB data will be discarded. Don't block. | |
409 | ||
410 | """ | |
411 | buf = self.sbdataq | |
412 | self.sbdataq = '' | |
413 | return buf | |
414 | ||
415 | def set_option_negotiation_callback(self, callback): | |
416 | """Provide a callback function called after each receipt of a telnet option.""" | |
417 | self.option_callback = callback | |
418 | ||
419 | def process_rawq(self): | |
420 | """Transfer from raw queue to cooked queue. | |
421 | ||
422 | Set self.eof when connection is closed. Don't block unless in | |
423 | the midst of an IAC sequence. | |
424 | ||
425 | """ | |
426 | buf = ['', ''] | |
427 | try: | |
428 | while self.rawq: | |
429 | c = self.rawq_getchar() | |
430 | if not self.iacseq: | |
431 | if c == theNULL: | |
432 | continue | |
433 | if c == "\021": | |
434 | continue | |
435 | if c != IAC: | |
436 | buf[self.sb] = buf[self.sb] + c | |
437 | continue | |
438 | else: | |
439 | self.iacseq += c | |
440 | elif len(self.iacseq) == 1: | |
441 | 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]' | |
442 | if c in (DO, DONT, WILL, WONT): | |
443 | self.iacseq += c | |
444 | continue | |
445 | ||
446 | self.iacseq = '' | |
447 | if c == IAC: | |
448 | buf[self.sb] = buf[self.sb] + c | |
449 | else: | |
450 | if c == SB: # SB ... SE start. | |
451 | self.sb = 1 | |
452 | self.sbdataq = '' | |
453 | elif c == SE: | |
454 | self.sb = 0 | |
455 | self.sbdataq = self.sbdataq + buf[1] | |
456 | buf[1] = '' | |
457 | if self.option_callback: | |
458 | # Callback is supposed to look into | |
459 | # the sbdataq | |
460 | self.option_callback(self.sock, c, NOOPT) | |
461 | else: | |
462 | # We can't offer automatic processing of | |
463 | # suboptions. Alas, we should not get any | |
464 | # unless we did a WILL/DO before. | |
465 | self.msg('IAC %d not recognized' % ord(c)) | |
466 | elif len(self.iacseq) == 2: | |
467 | cmd = self.iacseq[1] | |
468 | self.iacseq = '' | |
469 | opt = c | |
470 | if cmd in (DO, DONT): | |
471 | self.msg('IAC %s %d', | |
472 | cmd == DO and 'DO' or 'DONT', ord(opt)) | |
473 | if self.option_callback: | |
474 | self.option_callback(self.sock, cmd, opt) | |
475 | else: | |
476 | self.sock.sendall(IAC + WONT + opt) | |
477 | elif cmd in (WILL, WONT): | |
478 | self.msg('IAC %s %d', | |
479 | cmd == WILL and 'WILL' or 'WONT', ord(opt)) | |
480 | if self.option_callback: | |
481 | self.option_callback(self.sock, cmd, opt) | |
482 | else: | |
483 | self.sock.sendall(IAC + DONT + opt) | |
484 | except EOFError: # raised by self.rawq_getchar() | |
485 | self.iacseq = '' # Reset on EOF | |
486 | self.sb = 0 | |
487 | pass | |
488 | self.cookedq = self.cookedq + buf[0] | |
489 | self.sbdataq = self.sbdataq + buf[1] | |
490 | ||
491 | def rawq_getchar(self): | |
492 | """Get next char from raw queue. | |
493 | ||
494 | Block if no data is immediately available. Raise EOFError | |
495 | when connection is closed. | |
496 | ||
497 | """ | |
498 | if not self.rawq: | |
499 | self.fill_rawq() | |
500 | if self.eof: | |
501 | raise EOFError | |
502 | c = self.rawq[self.irawq] | |
503 | self.irawq = self.irawq + 1 | |
504 | if self.irawq >= len(self.rawq): | |
505 | self.rawq = '' | |
506 | self.irawq = 0 | |
507 | return c | |
508 | ||
509 | def fill_rawq(self): | |
510 | """Fill raw queue from exactly one recv() system call. | |
511 | ||
512 | Block if no data is immediately available. Set self.eof when | |
513 | connection is closed. | |
514 | ||
515 | """ | |
516 | if self.irawq >= len(self.rawq): | |
517 | self.rawq = '' | |
518 | self.irawq = 0 | |
519 | # The buffer size should be fairly small so as to avoid quadratic | |
520 | # behavior in process_rawq() above | |
521 | buf = self.sock.recv(50) | |
522 | self.msg("recv %r", buf) | |
523 | self.eof = (not buf) | |
524 | self.rawq = self.rawq + buf | |
525 | ||
526 | def sock_avail(self): | |
527 | """Test whether data is available on the socket.""" | |
528 | return select.select([self], [], [], 0) == ([self], [], []) | |
529 | ||
530 | def interact(self): | |
531 | """Interaction function, emulates a very dumb telnet client.""" | |
532 | if sys.platform == "win32": | |
533 | self.mt_interact() | |
534 | return | |
535 | while 1: | |
536 | rfd, wfd, xfd = select.select([self, sys.stdin], [], []) | |
537 | if self in rfd: | |
538 | try: | |
539 | text = self.read_eager() | |
540 | except EOFError: | |
541 | print '*** Connection closed by remote host ***' | |
542 | break | |
543 | if text: | |
544 | sys.stdout.write(text) | |
545 | sys.stdout.flush() | |
546 | if sys.stdin in rfd: | |
547 | line = sys.stdin.readline() | |
548 | if not line: | |
549 | break | |
550 | self.write(line) | |
551 | ||
552 | def mt_interact(self): | |
553 | """Multithreaded version of interact().""" | |
554 | import thread | |
555 | thread.start_new_thread(self.listener, ()) | |
556 | while 1: | |
557 | line = sys.stdin.readline() | |
558 | if not line: | |
559 | break | |
560 | self.write(line) | |
561 | ||
562 | def listener(self): | |
563 | """Helper for mt_interact() -- this executes in the other thread.""" | |
564 | while 1: | |
565 | try: | |
566 | data = self.read_eager() | |
567 | except EOFError: | |
568 | print '*** Connection closed by remote host ***' | |
569 | return | |
570 | if data: | |
571 | sys.stdout.write(data) | |
572 | else: | |
573 | sys.stdout.flush() | |
574 | ||
575 | def expect(self, list, timeout=None): | |
576 | """Read until one from a list of a regular expressions matches. | |
577 | ||
578 | The first argument is a list of regular expressions, either | |
579 | compiled (re.RegexObject instances) or uncompiled (strings). | |
580 | The optional second argument is a timeout, in seconds; default | |
581 | is no timeout. | |
582 | ||
583 | Return a tuple of three items: the index in the list of the | |
584 | first regular expression that matches; the match object | |
585 | returned; and the text read up till and including the match. | |
586 | ||
587 | If EOF is read and no text was read, raise EOFError. | |
588 | Otherwise, when nothing matches, return (-1, None, text) where | |
589 | text is the text received so far (may be the empty string if a | |
590 | timeout happened). | |
591 | ||
592 | If a regular expression ends with a greedy match (e.g. '.*') | |
593 | or if more than one expression can match the same input, the | |
594 | results are undeterministic, and may depend on the I/O timing. | |
595 | ||
596 | """ | |
597 | re = None | |
598 | list = list[:] | |
599 | indices = range(len(list)) | |
600 | for i in indices: | |
601 | if not hasattr(list[i], "search"): | |
602 | if not re: import re | |
603 | list[i] = re.compile(list[i]) | |
604 | while 1: | |
605 | self.process_rawq() | |
606 | for i in indices: | |
607 | m = list[i].search(self.cookedq) | |
608 | if m: | |
609 | e = m.end() | |
610 | text = self.cookedq[:e] | |
611 | self.cookedq = self.cookedq[e:] | |
612 | return (i, m, text) | |
613 | if self.eof: | |
614 | break | |
615 | if timeout is not None: | |
616 | r, w, x = select.select([self.fileno()], [], [], timeout) | |
617 | if not r: | |
618 | break | |
619 | self.fill_rawq() | |
620 | text = self.read_very_lazy() | |
621 | if not text and self.eof: | |
622 | raise EOFError | |
623 | return (-1, None, text) | |
624 | ||
625 | ||
626 | def test(): | |
627 | """Test program for telnetlib. | |
628 | ||
629 | Usage: python telnetlib.py [-d] ... [host [port]] | |
630 | ||
631 | Default host is localhost; default port is 23. | |
632 | ||
633 | """ | |
634 | debuglevel = 0 | |
635 | while sys.argv[1:] and sys.argv[1] == '-d': | |
636 | debuglevel = debuglevel+1 | |
637 | del sys.argv[1] | |
638 | host = 'localhost' | |
639 | if sys.argv[1:]: | |
640 | host = sys.argv[1] | |
641 | port = 0 | |
642 | if sys.argv[2:]: | |
643 | portstr = sys.argv[2] | |
644 | try: | |
645 | port = int(portstr) | |
646 | except ValueError: | |
647 | port = socket.getservbyname(portstr, 'tcp') | |
648 | tn = Telnet() | |
649 | tn.set_debuglevel(debuglevel) | |
650 | tn.open(host, port) | |
651 | tn.interact() | |
652 | tn.close() | |
653 | ||
654 | if __name__ == '__main__': | |
655 | test() |