Change the sense of a test in how the profiler interprets exception events.
[python/dscho.git] / Lib / ftplib.py
blob4aa6244c5e977161b84c5523ee5410e06f8648b0
1 """An FTP client class and some helper functions.
3 Based on RFC 959: File Transfer Protocol (FTP), by J. Postel and J. Reynolds
5 Example:
7 >>> from ftplib import FTP
8 >>> ftp = FTP('ftp.python.org') # connect to host, default port
9 >>> ftp.login() # default, i.e.: user anonymous, passwd user@hostname
10 '230 Guest login ok, access restrictions apply.'
11 >>> ftp.retrlines('LIST') # list directory contents
12 total 9
13 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
14 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
15 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
16 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
17 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
18 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
19 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
20 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
21 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
22 '226 Transfer complete.'
23 >>> ftp.quit()
24 '221 Goodbye.'
25 >>>
27 A nice test that reveals some of the network dialogue would be:
28 python ftplib.py -d localhost -l -p -l
29 """
32 # Changes and improvements suggested by Steve Majewski.
33 # Modified by Jack to work on the mac.
34 # Modified by Siebren to support docstrings and PASV.
37 import os
38 import sys
39 import string
41 # Import SOCKS module if it exists, else standard socket module socket
42 try:
43 import SOCKS; socket = SOCKS; del SOCKS # import SOCKS as socket
44 from socket import getfqdn; socket.getfqdn = getfqdn; del getfqdn
45 except ImportError:
46 import socket
48 __all__ = ["FTP","Netrc"]
50 # Magic number from <socket.h>
51 MSG_OOB = 0x1 # Process data out of band
54 # The standard FTP server control port
55 FTP_PORT = 21
58 # Exception raised when an error or invalid response is received
59 class Error(Exception): pass
60 class error_reply(Error): pass # unexpected [123]xx reply
61 class error_temp(Error): pass # 4xx errors
62 class error_perm(Error): pass # 5xx errors
63 class error_proto(Error): pass # response does not begin with [1-5]
66 # All exceptions (hopefully) that may be raised here and that aren't
67 # (always) programming errors on our side
68 all_errors = (Error, socket.error, IOError, EOFError)
71 # Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
72 CRLF = '\r\n'
75 # The class itself
76 class FTP:
78 '''An FTP client class.
80 To create a connection, call the class using these argument:
81 host, user, passwd, acct
82 These are all strings, and have default value ''.
83 Then use self.connect() with optional host and port argument.
85 To download a file, use ftp.retrlines('RETR ' + filename),
86 or ftp.retrbinary() with slightly different arguments.
87 To upload a file, use ftp.storlines() or ftp.storbinary(),
88 which have an open file as argument (see their definitions
89 below for details).
90 The download/upload functions first issue appropriate TYPE
91 and PORT or PASV commands.
92 '''
94 debugging = 0
95 host = ''
96 port = FTP_PORT
97 sock = None
98 file = None
99 welcome = None
100 passiveserver = 1
102 # Initialization method (called by class instantiation).
103 # Initialize host to localhost, port to standard ftp port
104 # Optional arguments are host (for connect()),
105 # and user, passwd, acct (for login())
106 def __init__(self, host='', user='', passwd='', acct=''):
107 if host:
108 self.connect(host)
109 if user: self.login(user, passwd, acct)
111 def connect(self, host = '', port = 0):
112 '''Connect to host. Arguments are:
113 - host: hostname to connect to (string, default previous host)
114 - port: port to connect to (integer, default previous port)'''
115 if host: self.host = host
116 if port: self.port = port
117 self.passiveserver = 0
118 msg = "getaddrinfo returns an empty list"
119 for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
120 af, socktype, proto, canonname, sa = res
121 try:
122 self.sock = socket.socket(af, socktype, proto)
123 self.sock.connect(sa)
124 except socket.error, msg:
125 self.sock.close()
126 self.sock = None
127 continue
128 break
129 if not self.sock:
130 raise socket.error, msg
131 self.af = af
132 self.file = self.sock.makefile('rb')
133 self.welcome = self.getresp()
134 return self.welcome
136 def getwelcome(self):
137 '''Get the welcome message from the server.
138 (this is read and squirreled away by connect())'''
139 if self.debugging:
140 print '*welcome*', self.sanitize(self.welcome)
141 return self.welcome
143 def set_debuglevel(self, level):
144 '''Set the debugging level.
145 The required argument level means:
146 0: no debugging output (default)
147 1: print commands and responses but not body text etc.
148 2: also print raw lines read and sent before stripping CR/LF'''
149 self.debugging = level
150 debug = set_debuglevel
152 def set_pasv(self, val):
153 '''Use passive or active mode for data transfers.
154 With a false argument, use the normal PORT mode,
155 With a true argument, use the PASV command.'''
156 self.passiveserver = val
158 # Internal: "sanitize" a string for printing
159 def sanitize(self, s):
160 if s[:5] == 'pass ' or s[:5] == 'PASS ':
161 i = len(s)
162 while i > 5 and s[i-1] in '\r\n':
163 i = i-1
164 s = s[:5] + '*'*(i-5) + s[i:]
165 return `s`
167 # Internal: send one line to the server, appending CRLF
168 def putline(self, line):
169 line = line + CRLF
170 if self.debugging > 1: print '*put*', self.sanitize(line)
171 self.sock.send(line)
173 # Internal: send one command to the server (through putline())
174 def putcmd(self, line):
175 if self.debugging: print '*cmd*', self.sanitize(line)
176 self.putline(line)
178 # Internal: return one line from the server, stripping CRLF.
179 # Raise EOFError if the connection is closed
180 def getline(self):
181 line = self.file.readline()
182 if self.debugging > 1:
183 print '*get*', self.sanitize(line)
184 if not line: raise EOFError
185 if line[-2:] == CRLF: line = line[:-2]
186 elif line[-1:] in CRLF: line = line[:-1]
187 return line
189 # Internal: get a response from the server, which may possibly
190 # consist of multiple lines. Return a single string with no
191 # trailing CRLF. If the response consists of multiple lines,
192 # these are separated by '\n' characters in the string
193 def getmultiline(self):
194 line = self.getline()
195 if line[3:4] == '-':
196 code = line[:3]
197 while 1:
198 nextline = self.getline()
199 line = line + ('\n' + nextline)
200 if nextline[:3] == code and \
201 nextline[3:4] != '-':
202 break
203 return line
205 # Internal: get a response from the server.
206 # Raise various errors if the response indicates an error
207 def getresp(self):
208 resp = self.getmultiline()
209 if self.debugging: print '*resp*', self.sanitize(resp)
210 self.lastresp = resp[:3]
211 c = resp[:1]
212 if c == '4':
213 raise error_temp, resp
214 if c == '5':
215 raise error_perm, resp
216 if c not in '123':
217 raise error_proto, resp
218 return resp
220 def voidresp(self):
221 """Expect a response beginning with '2'."""
222 resp = self.getresp()
223 if resp[0] != '2':
224 raise error_reply, resp
225 return resp
227 def abort(self):
228 '''Abort a file transfer. Uses out-of-band data.
229 This does not follow the procedure from the RFC to send Telnet
230 IP and Synch; that doesn't seem to work with the servers I've
231 tried. Instead, just send the ABOR command as OOB data.'''
232 line = 'ABOR' + CRLF
233 if self.debugging > 1: print '*put urgent*', self.sanitize(line)
234 self.sock.send(line, MSG_OOB)
235 resp = self.getmultiline()
236 if resp[:3] not in ('426', '226'):
237 raise error_proto, resp
239 def sendcmd(self, cmd):
240 '''Send a command and return the response.'''
241 self.putcmd(cmd)
242 return self.getresp()
244 def voidcmd(self, cmd):
245 """Send a command and expect a response beginning with '2'."""
246 self.putcmd(cmd)
247 return self.voidresp()
249 def sendport(self, host, port):
250 '''Send a PORT command with the current host and the given
251 port number.
253 hbytes = host.split('.')
254 pbytes = [`port/256`, `port%256`]
255 bytes = hbytes + pbytes
256 cmd = 'PORT ' + ','.join(bytes)
257 return self.voidcmd(cmd)
259 def sendeprt(self, host, port):
260 '''Send a EPRT command with the current host and the given port number.'''
261 af = 0
262 if self.af == socket.AF_INET:
263 af = 1
264 if self.af == socket.AF_INET6:
265 af = 2
266 if af == 0:
267 raise error_proto, 'unsupported address family'
268 fields = ['', `af`, host, `port`, '']
269 cmd = 'EPRT ' + string.joinfields(fields, '|')
270 return self.voidcmd(cmd)
272 def makeport(self):
273 '''Create a new socket and send a PORT command for it.'''
274 msg = "getaddrinfo returns an empty list"
275 for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
276 af, socktype, proto, canonname, sa = res
277 try:
278 sock = socket.socket(af, socktype, proto)
279 sock.bind(sa)
280 except socket.error, msg:
281 sock.close()
282 sock = None
283 continue
284 break
285 if not sock:
286 raise socket.error, msg
287 sock.listen(1)
288 port = sock.getsockname()[1] # Get proper port
289 host = self.sock.getsockname()[0] # Get proper host
290 if self.af == socket.AF_INET:
291 resp = self.sendport(host, port)
292 else:
293 resp = self.sendeprt(host, port)
294 return sock
296 def makepasv(self):
297 if self.af == socket.AF_INET:
298 host, port = parse227(self.sendcmd('PASV'))
299 else:
300 host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
301 return host, port
303 def ntransfercmd(self, cmd, rest=None):
304 """Initiate a transfer over the data connection.
306 If the transfer is active, send a port command and the
307 transfer command, and accept the connection. If the server is
308 passive, send a pasv command, connect to it, and start the
309 transfer command. Either way, return the socket for the
310 connection and the expected size of the transfer. The
311 expected size may be None if it could not be determined.
313 Optional `rest' argument can be a string that is sent as the
314 argument to a RESTART command. This is essentially a server
315 marker used to tell the server to skip over any data up to the
316 given marker.
318 size = None
319 if self.passiveserver:
320 host, port = self.makepasv()
321 af, socktype, proto, canon, sa = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0]
322 conn = socket.socket(af, socktype, proto)
323 conn.connect(sa)
324 if rest is not None:
325 self.sendcmd("REST %s" % rest)
326 resp = self.sendcmd(cmd)
327 if resp[0] != '1':
328 raise error_reply, resp
329 else:
330 sock = self.makeport()
331 if rest is not None:
332 self.sendcmd("REST %s" % rest)
333 resp = self.sendcmd(cmd)
334 if resp[0] != '1':
335 raise error_reply, resp
336 conn, sockaddr = sock.accept()
337 if resp[:3] == '150':
338 # this is conditional in case we received a 125
339 size = parse150(resp)
340 return conn, size
342 def transfercmd(self, cmd, rest=None):
343 """Like nstransfercmd() but returns only the socket."""
344 return self.ntransfercmd(cmd, rest)[0]
346 def login(self, user = '', passwd = '', acct = ''):
347 '''Login, default anonymous.'''
348 if not user: user = 'anonymous'
349 if not passwd: passwd = ''
350 if not acct: acct = ''
351 if user == 'anonymous' and passwd in ('', '-'):
352 # get fully qualified domain name of local host
353 thishost = socket.getfqdn()
354 try:
355 if os.environ.has_key('LOGNAME'):
356 realuser = os.environ['LOGNAME']
357 elif os.environ.has_key('USER'):
358 realuser = os.environ['USER']
359 else:
360 realuser = 'anonymous'
361 except AttributeError:
362 # Not all systems have os.environ....
363 realuser = 'anonymous'
364 passwd = passwd + realuser + '@' + thishost
365 resp = self.sendcmd('USER ' + user)
366 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
367 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
368 if resp[0] != '2':
369 raise error_reply, resp
370 return resp
372 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
373 """Retrieve data in binary mode.
375 `cmd' is a RETR command. `callback' is a callback function is
376 called for each block. No more than `blocksize' number of
377 bytes will be read from the socket. Optional `rest' is passed
378 to transfercmd().
380 A new port is created for you. Return the response code.
382 self.voidcmd('TYPE I')
383 conn = self.transfercmd(cmd, rest)
384 while 1:
385 data = conn.recv(blocksize)
386 if not data:
387 break
388 callback(data)
389 conn.close()
390 return self.voidresp()
392 def retrlines(self, cmd, callback = None):
393 '''Retrieve data in line mode.
394 The argument is a RETR or LIST command.
395 The callback function (2nd argument) is called for each line,
396 with trailing CRLF stripped. This creates a new port for you.
397 print_line() is the default callback.'''
398 if not callback: callback = print_line
399 resp = self.sendcmd('TYPE A')
400 conn = self.transfercmd(cmd)
401 fp = conn.makefile('rb')
402 while 1:
403 line = fp.readline()
404 if self.debugging > 2: print '*retr*', `line`
405 if not line:
406 break
407 if line[-2:] == CRLF:
408 line = line[:-2]
409 elif line[-1:] == '\n':
410 line = line[:-1]
411 callback(line)
412 fp.close()
413 conn.close()
414 return self.voidresp()
416 def storbinary(self, cmd, fp, blocksize=8192):
417 '''Store a file in binary mode.'''
418 self.voidcmd('TYPE I')
419 conn = self.transfercmd(cmd)
420 while 1:
421 buf = fp.read(blocksize)
422 if not buf: break
423 conn.send(buf)
424 conn.close()
425 return self.voidresp()
427 def storlines(self, cmd, fp):
428 '''Store a file in line mode.'''
429 self.voidcmd('TYPE A')
430 conn = self.transfercmd(cmd)
431 while 1:
432 buf = fp.readline()
433 if not buf: break
434 if buf[-2:] != CRLF:
435 if buf[-1] in CRLF: buf = buf[:-1]
436 buf = buf + CRLF
437 conn.send(buf)
438 conn.close()
439 return self.voidresp()
441 def acct(self, password):
442 '''Send new account name.'''
443 cmd = 'ACCT ' + password
444 return self.voidcmd(cmd)
446 def nlst(self, *args):
447 '''Return a list of files in a given directory (default the current).'''
448 cmd = 'NLST'
449 for arg in args:
450 cmd = cmd + (' ' + arg)
451 files = []
452 self.retrlines(cmd, files.append)
453 return files
455 def dir(self, *args):
456 '''List a directory in long form.
457 By default list current directory to stdout.
458 Optional last argument is callback function; all
459 non-empty arguments before it are concatenated to the
460 LIST command. (This *should* only be used for a pathname.)'''
461 cmd = 'LIST'
462 func = None
463 if args[-1:] and type(args[-1]) != type(''):
464 args, func = args[:-1], args[-1]
465 for arg in args:
466 if arg:
467 cmd = cmd + (' ' + arg)
468 self.retrlines(cmd, func)
470 def rename(self, fromname, toname):
471 '''Rename a file.'''
472 resp = self.sendcmd('RNFR ' + fromname)
473 if resp[0] != '3':
474 raise error_reply, resp
475 return self.voidcmd('RNTO ' + toname)
477 def delete(self, filename):
478 '''Delete a file.'''
479 resp = self.sendcmd('DELE ' + filename)
480 if resp[:3] in ('250', '200'):
481 return resp
482 elif resp[:1] == '5':
483 raise error_perm, resp
484 else:
485 raise error_reply, resp
487 def cwd(self, dirname):
488 '''Change to a directory.'''
489 if dirname == '..':
490 try:
491 return self.voidcmd('CDUP')
492 except error_perm, msg:
493 if msg[:3] != '500':
494 raise error_perm, msg
495 elif dirname == '':
496 dirname = '.' # does nothing, but could return error
497 cmd = 'CWD ' + dirname
498 return self.voidcmd(cmd)
500 def size(self, filename):
501 '''Retrieve the size of a file.'''
502 # Note that the RFC doesn't say anything about 'SIZE'
503 resp = self.sendcmd('SIZE ' + filename)
504 if resp[:3] == '213':
505 return int(resp[3:].strip())
507 def mkd(self, dirname):
508 '''Make a directory, return its full pathname.'''
509 resp = self.sendcmd('MKD ' + dirname)
510 return parse257(resp)
512 def rmd(self, dirname):
513 '''Remove a directory.'''
514 return self.voidcmd('RMD ' + dirname)
516 def pwd(self):
517 '''Return current working directory.'''
518 resp = self.sendcmd('PWD')
519 return parse257(resp)
521 def quit(self):
522 '''Quit, and close the connection.'''
523 resp = self.voidcmd('QUIT')
524 self.close()
525 return resp
527 def close(self):
528 '''Close the connection without assuming anything about it.'''
529 if self.file:
530 self.file.close()
531 self.sock.close()
532 self.file = self.sock = None
535 _150_re = None
537 def parse150(resp):
538 '''Parse the '150' response for a RETR request.
539 Returns the expected transfer size or None; size is not guaranteed to
540 be present in the 150 message.
542 if resp[:3] != '150':
543 raise error_reply, resp
544 global _150_re
545 if _150_re is None:
546 import re
547 _150_re = re.compile("150 .* \((\d+) bytes\)", re.IGNORECASE)
548 m = _150_re.match(resp)
549 if m:
550 return int(m.group(1))
551 return None
554 _227_re = None
556 def parse227(resp):
557 '''Parse the '227' response for a PASV request.
558 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
559 Return ('host.addr.as.numbers', port#) tuple.'''
561 if resp[:3] != '227':
562 raise error_reply, resp
563 global _227_re
564 if _227_re is None:
565 import re
566 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)')
567 m = _227_re.search(resp)
568 if not m:
569 raise error_proto, resp
570 numbers = m.groups()
571 host = '.'.join(numbers[:4])
572 port = (int(numbers[4]) << 8) + int(numbers[5])
573 return host, port
576 def parse229(resp, peer):
577 '''Parse the '229' response for a EPSV request.
578 Raises error_proto if it does not contain '(|||port|)'
579 Return ('host.addr.as.numbers', port#) tuple.'''
581 if resp[:3] <> '229':
582 raise error_reply, resp
583 left = string.find(resp, '(')
584 if left < 0: raise error_proto, resp
585 right = string.find(resp, ')', left + 1)
586 if right < 0:
587 raise error_proto, resp # should contain '(|||port|)'
588 if resp[left + 1] <> resp[right - 1]:
589 raise error_proto, resp
590 parts = string.split(resp[left + 1:right], resp[left+1])
591 if len(parts) <> 5:
592 raise error_proto, resp
593 host = peer[0]
594 port = string.atoi(parts[3])
595 return host, port
598 def parse257(resp):
599 '''Parse the '257' response for a MKD or PWD request.
600 This is a response to a MKD or PWD request: a directory name.
601 Returns the directoryname in the 257 reply.'''
603 if resp[:3] != '257':
604 raise error_reply, resp
605 if resp[3:5] != ' "':
606 return '' # Not compliant to RFC 959, but UNIX ftpd does this
607 dirname = ''
608 i = 5
609 n = len(resp)
610 while i < n:
611 c = resp[i]
612 i = i+1
613 if c == '"':
614 if i >= n or resp[i] != '"':
615 break
616 i = i+1
617 dirname = dirname + c
618 return dirname
621 def print_line(line):
622 '''Default retrlines callback to print a line.'''
623 print line
626 def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
627 '''Copy file from one FTP-instance to another.'''
628 if not targetname: targetname = sourcename
629 type = 'TYPE ' + type
630 source.voidcmd(type)
631 target.voidcmd(type)
632 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
633 target.sendport(sourcehost, sourceport)
634 # RFC 959: the user must "listen" [...] BEFORE sending the
635 # transfer request.
636 # So: STOR before RETR, because here the target is a "user".
637 treply = target.sendcmd('STOR ' + targetname)
638 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
639 sreply = source.sendcmd('RETR ' + sourcename)
640 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
641 source.voidresp()
642 target.voidresp()
645 class Netrc:
646 """Class to parse & provide access to 'netrc' format files.
648 See the netrc(4) man page for information on the file format.
650 WARNING: This class is obsolete -- use module netrc instead.
653 __defuser = None
654 __defpasswd = None
655 __defacct = None
657 def __init__(self, filename=None):
658 if not filename:
659 if os.environ.has_key("HOME"):
660 filename = os.path.join(os.environ["HOME"],
661 ".netrc")
662 else:
663 raise IOError, \
664 "specify file to load or set $HOME"
665 self.__hosts = {}
666 self.__macros = {}
667 fp = open(filename, "r")
668 in_macro = 0
669 while 1:
670 line = fp.readline()
671 if not line: break
672 if in_macro and line.strip():
673 macro_lines.append(line)
674 continue
675 elif in_macro:
676 self.__macros[macro_name] = tuple(macro_lines)
677 in_macro = 0
678 words = line.split()
679 host = user = passwd = acct = None
680 default = 0
681 i = 0
682 while i < len(words):
683 w1 = words[i]
684 if i+1 < len(words):
685 w2 = words[i + 1]
686 else:
687 w2 = None
688 if w1 == 'default':
689 default = 1
690 elif w1 == 'machine' and w2:
691 host = w2.lower()
692 i = i + 1
693 elif w1 == 'login' and w2:
694 user = w2
695 i = i + 1
696 elif w1 == 'password' and w2:
697 passwd = w2
698 i = i + 1
699 elif w1 == 'account' and w2:
700 acct = w2
701 i = i + 1
702 elif w1 == 'macdef' and w2:
703 macro_name = w2
704 macro_lines = []
705 in_macro = 1
706 break
707 i = i + 1
708 if default:
709 self.__defuser = user or self.__defuser
710 self.__defpasswd = passwd or self.__defpasswd
711 self.__defacct = acct or self.__defacct
712 if host:
713 if self.__hosts.has_key(host):
714 ouser, opasswd, oacct = \
715 self.__hosts[host]
716 user = user or ouser
717 passwd = passwd or opasswd
718 acct = acct or oacct
719 self.__hosts[host] = user, passwd, acct
720 fp.close()
722 def get_hosts(self):
723 """Return a list of hosts mentioned in the .netrc file."""
724 return self.__hosts.keys()
726 def get_account(self, host):
727 """Returns login information for the named host.
729 The return value is a triple containing userid,
730 password, and the accounting field.
733 host = host.lower()
734 user = passwd = acct = None
735 if self.__hosts.has_key(host):
736 user, passwd, acct = self.__hosts[host]
737 user = user or self.__defuser
738 passwd = passwd or self.__defpasswd
739 acct = acct or self.__defacct
740 return user, passwd, acct
742 def get_macros(self):
743 """Return a list of all defined macro names."""
744 return self.__macros.keys()
746 def get_macro(self, macro):
747 """Return a sequence of lines which define a named macro."""
748 return self.__macros[macro]
752 def test():
753 '''Test program.
754 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...'''
756 debugging = 0
757 rcfile = None
758 while sys.argv[1] == '-d':
759 debugging = debugging+1
760 del sys.argv[1]
761 if sys.argv[1][:2] == '-r':
762 # get name of alternate ~/.netrc file:
763 rcfile = sys.argv[1][2:]
764 del sys.argv[1]
765 host = sys.argv[1]
766 ftp = FTP(host)
767 ftp.set_debuglevel(debugging)
768 userid = passwd = acct = ''
769 try:
770 netrc = Netrc(rcfile)
771 except IOError:
772 if rcfile is not None:
773 sys.stderr.write("Could not open account file"
774 " -- using anonymous login.")
775 else:
776 try:
777 userid, passwd, acct = netrc.get_account(host)
778 except KeyError:
779 # no account for host
780 sys.stderr.write(
781 "No account -- using anonymous login.")
782 ftp.login(userid, passwd, acct)
783 for file in sys.argv[2:]:
784 if file[:2] == '-l':
785 ftp.dir(file[2:])
786 elif file[:2] == '-d':
787 cmd = 'CWD'
788 if file[2:]: cmd = cmd + ' ' + file[2:]
789 resp = ftp.sendcmd(cmd)
790 elif file == '-p':
791 ftp.set_pasv(not ftp.passiveserver)
792 else:
793 ftp.retrbinary('RETR ' + file, \
794 sys.stdout.write, 1024)
795 ftp.quit()
798 if __name__ == '__main__':
799 test()