0001 """An FTP client class and some helper functions. 0002 0003 Based on RFC 959: File Transfer Protocol (FTP), by J. Postel and J. Reynolds 0004 0005 Example: 0006 0007 >>> from ftplib import FTP 0008 >>> ftp = FTP('ftp.python.org') # connect to host, default port 0009 >>> ftp.login() # default, i.e.: user anonymous, passwd anonymous@ 0010 '230 Guest login ok, access restrictions apply.' 0011 >>> ftp.retrlines('LIST') # list directory contents 0012 total 9 0013 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 . 0014 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .. 0015 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin 0016 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc 0017 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming 0018 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib 0019 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub 0020 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr 0021 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg 0022 '226 Transfer complete.' 0023 >>> ftp.quit() 0024 '221 Goodbye.' 0025 >>> 0026 0027 A nice test that reveals some of the network dialogue would be: 0028 python ftplib.py -d localhost -l -p -l 0029 """ 0030 0031 # 0032 # Changes and improvements suggested by Steve Majewski. 0033 # Modified by Jack to work on the mac. 0034 # Modified by Siebren to support docstrings and PASV. 0035 # 0036 0037 import os 0038 import sys 0039 0040 # Import SOCKS module if it exists, else standard socket module socket 0041 try: 0042 import SOCKS; socket = SOCKS; del SOCKS # import SOCKS as socket 0043 from socket import getfqdn; socket.getfqdn = getfqdn; del getfqdn 0044 except ImportError: 0045 import socket 0046 0047 __all__ = ["FTP","Netrc"] 0048 0049 # Magic number from <socket.h> 0050 MSG_OOB = 0x1 # Process data out of band 0051 0052 0053 # The standard FTP server control port 0054 FTP_PORT = 21 0055 0056 0057 # Exception raised when an error or invalid response is received 0058 class Error(Exception): pass 0059 class error_reply(Error): pass # unexpected [123]xx reply 0060 class error_temp(Error): pass # 4xx errors 0061 class error_perm(Error): pass # 5xx errors 0062 class error_proto(Error): pass # response does not begin with [1-5] 0063 0064 0065 # All exceptions (hopefully) that may be raised here and that aren't 0066 # (always) programming errors on our side 0067 all_errors = (Error, socket.error, IOError, EOFError) 0068 0069 0070 # Line terminators (we always output CRLF, but accept any of CRLF, CR, LF) 0071 CRLF = '\r\n' 0072 0073 0074 # The class itself 0075 class FTP: 0076 0077 '''An FTP client class. 0078 0079 To create a connection, call the class using these argument: 0080 host, user, passwd, acct 0081 These are all strings, and have default value ''. 0082 Then use self.connect() with optional host and port argument. 0083 0084 To download a file, use ftp.retrlines('RETR ' + filename), 0085 or ftp.retrbinary() with slightly different arguments. 0086 To upload a file, use ftp.storlines() or ftp.storbinary(), 0087 which have an open file as argument (see their definitions 0088 below for details). 0089 The download/upload functions first issue appropriate TYPE 0090 and PORT or PASV commands. 0091 ''' 0092 0093 debugging = 0 0094 host = '' 0095 port = FTP_PORT 0096 sock = None 0097 file = None 0098 welcome = None 0099 passiveserver = 1 0100 0101 # Initialization method (called by class instantiation). 0102 # Initialize host to localhost, port to standard ftp port 0103 # Optional arguments are host (for connect()), 0104 # and user, passwd, acct (for login()) 0105 def __init__(self, host='', user='', passwd='', acct=''): 0106 if host: 0107 self.connect(host) 0108 if user: self.login(user, passwd, acct) 0109 0110 def connect(self, host = '', port = 0): 0111 '''Connect to host. Arguments are: 0112 - host: hostname to connect to (string, default previous host) 0113 - port: port to connect to (integer, default previous port)''' 0114 if host: self.host = host 0115 if port: self.port = port 0116 msg = "getaddrinfo returns an empty list" 0117 for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): 0118 af, socktype, proto, canonname, sa = res 0119 try: 0120 self.sock = socket.socket(af, socktype, proto) 0121 self.sock.connect(sa) 0122 except socket.error, msg: 0123 if self.sock: 0124 self.sock.close() 0125 self.sock = None 0126 continue 0127 break 0128 if not self.sock: 0129 raise socket.error, msg 0130 self.af = af 0131 self.file = self.sock.makefile('rb') 0132 self.welcome = self.getresp() 0133 return self.welcome 0134 0135 def getwelcome(self): 0136 '''Get the welcome message from the server. 0137 (this is read and squirreled away by connect())''' 0138 if self.debugging: 0139 print '*welcome*', self.sanitize(self.welcome) 0140 return self.welcome 0141 0142 def set_debuglevel(self, level): 0143 '''Set the debugging level. 0144 The required argument level means: 0145 0: no debugging output (default) 0146 1: print commands and responses but not body text etc. 0147 2: also print raw lines read and sent before stripping CR/LF''' 0148 self.debugging = level 0149 debug = set_debuglevel 0150 0151 def set_pasv(self, val): 0152 '''Use passive or active mode for data transfers. 0153 With a false argument, use the normal PORT mode, 0154 With a true argument, use the PASV command.''' 0155 self.passiveserver = val 0156 0157 # Internal: "sanitize" a string for printing 0158 def sanitize(self, s): 0159 if s[:5] == 'pass ' or s[:5] == 'PASS ': 0160 i = len(s) 0161 while i > 5 and s[i-1] in '\r\n': 0162 i = i-1 0163 s = s[:5] + '*'*(i-5) + s[i:] 0164 return repr(s) 0165 0166 # Internal: send one line to the server, appending CRLF 0167 def putline(self, line): 0168 line = line + CRLF 0169 if self.debugging > 1: print '*put*', self.sanitize(line) 0170 self.sock.sendall(line) 0171 0172 # Internal: send one command to the server (through putline()) 0173 def putcmd(self, line): 0174 if self.debugging: print '*cmd*', self.sanitize(line) 0175 self.putline(line) 0176 0177 # Internal: return one line from the server, stripping CRLF. 0178 # Raise EOFError if the connection is closed 0179 def getline(self): 0180 line = self.file.readline() 0181 if self.debugging > 1: 0182 print '*get*', self.sanitize(line) 0183 if not line: raise EOFError 0184 if line[-2:] == CRLF: line = line[:-2] 0185 elif line[-1:] in CRLF: line = line[:-1] 0186 return line 0187 0188 # Internal: get a response from the server, which may possibly 0189 # consist of multiple lines. Return a single string with no 0190 # trailing CRLF. If the response consists of multiple lines, 0191 # these are separated by '\n' characters in the string 0192 def getmultiline(self): 0193 line = self.getline() 0194 if line[3:4] == '-': 0195 code = line[:3] 0196 while 1: 0197 nextline = self.getline() 0198 line = line + ('\n' + nextline) 0199 if nextline[:3] == code and \ 0200 nextline[3:4] != '-': 0201 break 0202 return line 0203 0204 # Internal: get a response from the server. 0205 # Raise various errors if the response indicates an error 0206 def getresp(self): 0207 resp = self.getmultiline() 0208 if self.debugging: print '*resp*', self.sanitize(resp) 0209 self.lastresp = resp[:3] 0210 c = resp[:1] 0211 if c == '4': 0212 raise error_temp, resp 0213 if c == '5': 0214 raise error_perm, resp 0215 if c not in '123': 0216 raise error_proto, resp 0217 return resp 0218 0219 def voidresp(self): 0220 """Expect a response beginning with '2'.""" 0221 resp = self.getresp() 0222 if resp[0] != '2': 0223 raise error_reply, resp 0224 return resp 0225 0226 def abort(self): 0227 '''Abort a file transfer. Uses out-of-band data. 0228 This does not follow the procedure from the RFC to send Telnet 0229 IP and Synch; that doesn't seem to work with the servers I've 0230 tried. Instead, just send the ABOR command as OOB data.''' 0231 line = 'ABOR' + CRLF 0232 if self.debugging > 1: print '*put urgent*', self.sanitize(line) 0233 self.sock.sendall(line, MSG_OOB) 0234 resp = self.getmultiline() 0235 if resp[:3] not in ('426', '226'): 0236 raise error_proto, resp 0237 0238 def sendcmd(self, cmd): 0239 '''Send a command and return the response.''' 0240 self.putcmd(cmd) 0241 return self.getresp() 0242 0243 def voidcmd(self, cmd): 0244 """Send a command and expect a response beginning with '2'.""" 0245 self.putcmd(cmd) 0246 return self.voidresp() 0247 0248 def sendport(self, host, port): 0249 '''Send a PORT command with the current host and the given 0250 port number. 0251 ''' 0252 hbytes = host.split('.') 0253 pbytes = [repr(port/256), repr(port%256)] 0254 bytes = hbytes + pbytes 0255 cmd = 'PORT ' + ','.join(bytes) 0256 return self.voidcmd(cmd) 0257 0258 def sendeprt(self, host, port): 0259 '''Send a EPRT command with the current host and the given port number.''' 0260 af = 0 0261 if self.af == socket.AF_INET: 0262 af = 1 0263 if self.af == socket.AF_INET6: 0264 af = 2 0265 if af == 0: 0266 raise error_proto, 'unsupported address family' 0267 fields = ['', repr(af), host, repr(port), ''] 0268 cmd = 'EPRT ' + '|'.join(fields) 0269 return self.voidcmd(cmd) 0270 0271 def makeport(self): 0272 '''Create a new socket and send a PORT command for it.''' 0273 msg = "getaddrinfo returns an empty list" 0274 sock = None 0275 for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): 0276 af, socktype, proto, canonname, sa = res 0277 try: 0278 sock = socket.socket(af, socktype, proto) 0279 sock.bind(sa) 0280 except socket.error, msg: 0281 if sock: 0282 sock.close() 0283 sock = None 0284 continue 0285 break 0286 if not sock: 0287 raise socket.error, msg 0288 sock.listen(1) 0289 port = sock.getsockname()[1] # Get proper port 0290 host = self.sock.getsockname()[0] # Get proper host 0291 if self.af == socket.AF_INET: 0292 resp = self.sendport(host, port) 0293 else: 0294 resp = self.sendeprt(host, port) 0295 return sock 0296 0297 def makepasv(self): 0298 if self.af == socket.AF_INET: 0299 host, port = parse227(self.sendcmd('PASV')) 0300 else: 0301 host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername()) 0302 return host, port 0303 0304 def ntransfercmd(self, cmd, rest=None): 0305 """Initiate a transfer over the data connection. 0306 0307 If the transfer is active, send a port command and the 0308 transfer command, and accept the connection. If the server is 0309 passive, send a pasv command, connect to it, and start the 0310 transfer command. Either way, return the socket for the 0311 connection and the expected size of the transfer. The 0312 expected size may be None if it could not be determined. 0313 0314 Optional `rest' argument can be a string that is sent as the 0315 argument to a RESTART command. This is essentially a server 0316 marker used to tell the server to skip over any data up to the 0317 given marker. 0318 """ 0319 size = None 0320 if self.passiveserver: 0321 host, port = self.makepasv() 0322 af, socktype, proto, canon, sa = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] 0323 conn = socket.socket(af, socktype, proto) 0324 conn.connect(sa) 0325 if rest is not None: 0326 self.sendcmd("REST %s" % rest) 0327 resp = self.sendcmd(cmd) 0328 if resp[0] != '1': 0329 raise error_reply, resp 0330 else: 0331 sock = self.makeport() 0332 if rest is not None: 0333 self.sendcmd("REST %s" % rest) 0334 resp = self.sendcmd(cmd) 0335 if resp[0] != '1': 0336 raise error_reply, resp 0337 conn, sockaddr = sock.accept() 0338 if resp[:3] == '150': 0339 # this is conditional in case we received a 125 0340 size = parse150(resp) 0341 return conn, size 0342 0343 def transfercmd(self, cmd, rest=None): 0344 """Like ntransfercmd() but returns only the socket.""" 0345 return self.ntransfercmd(cmd, rest)[0] 0346 0347 def login(self, user = '', passwd = '', acct = ''): 0348 '''Login, default anonymous.''' 0349 if not user: user = 'anonymous' 0350 if not passwd: passwd = '' 0351 if not acct: acct = '' 0352 if user == 'anonymous' and passwd in ('', '-'): 0353 # If there is no anonymous ftp password specified 0354 # then we'll just use anonymous@ 0355 # We don't send any other thing because: 0356 # - We want to remain anonymous 0357 # - We want to stop SPAM 0358 # - We don't want to let ftp sites to discriminate by the user, 0359 # host or country. 0360 passwd = passwd + 'anonymous@' 0361 resp = self.sendcmd('USER ' + user) 0362 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd) 0363 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct) 0364 if resp[0] != '2': 0365 raise error_reply, resp 0366 return resp 0367 0368 def retrbinary(self, cmd, callback, blocksize=8192, rest=None): 0369 """Retrieve data in binary mode. 0370 0371 `cmd' is a RETR command. `callback' is a callback function is 0372 called for each block. No more than `blocksize' number of 0373 bytes will be read from the socket. Optional `rest' is passed 0374 to transfercmd(). 0375 0376 A new port is created for you. Return the response code. 0377 """ 0378 self.voidcmd('TYPE I') 0379 conn = self.transfercmd(cmd, rest) 0380 while 1: 0381 data = conn.recv(blocksize) 0382 if not data: 0383 break 0384 callback(data) 0385 conn.close() 0386 return self.voidresp() 0387 0388 def retrlines(self, cmd, callback = None): 0389 '''Retrieve data in line mode. 0390 The argument is a RETR or LIST command. 0391 The callback function (2nd argument) is called for each line, 0392 with trailing CRLF stripped. This creates a new port for you. 0393 print_line() is the default callback.''' 0394 if callback is None: callback = print_line 0395 resp = self.sendcmd('TYPE A') 0396 conn = self.transfercmd(cmd) 0397 fp = conn.makefile('rb') 0398 while 1: 0399 line = fp.readline() 0400 if self.debugging > 2: print '*retr*', repr(line) 0401 if not line: 0402 break 0403 if line[-2:] == CRLF: 0404 line = line[:-2] 0405 elif line[-1:] == '\n': 0406 line = line[:-1] 0407 callback(line) 0408 fp.close() 0409 conn.close() 0410 return self.voidresp() 0411 0412 def storbinary(self, cmd, fp, blocksize=8192): 0413 '''Store a file in binary mode.''' 0414 self.voidcmd('TYPE I') 0415 conn = self.transfercmd(cmd) 0416 while 1: 0417 buf = fp.read(blocksize) 0418 if not buf: break 0419 conn.sendall(buf) 0420 conn.close() 0421 return self.voidresp() 0422 0423 def storlines(self, cmd, fp): 0424 '''Store a file in line mode.''' 0425 self.voidcmd('TYPE A') 0426 conn = self.transfercmd(cmd) 0427 while 1: 0428 buf = fp.readline() 0429 if not buf: break 0430 if buf[-2:] != CRLF: 0431 if buf[-1] in CRLF: buf = buf[:-1] 0432 buf = buf + CRLF 0433 conn.sendall(buf) 0434 conn.close() 0435 return self.voidresp() 0436 0437 def acct(self, password): 0438 '''Send new account name.''' 0439 cmd = 'ACCT ' + password 0440 return self.voidcmd(cmd) 0441 0442 def nlst(self, *args): 0443 '''Return a list of files in a given directory (default the current).''' 0444 cmd = 'NLST' 0445 for arg in args: 0446 cmd = cmd + (' ' + arg) 0447 files = [] 0448 self.retrlines(cmd, files.append) 0449 return files 0450 0451 def dir(self, *args): 0452 '''List a directory in long form. 0453 By default list current directory to stdout. 0454 Optional last argument is callback function; all 0455 non-empty arguments before it are concatenated to the 0456 LIST command. (This *should* only be used for a pathname.)''' 0457 cmd = 'LIST' 0458 func = None 0459 if args[-1:] and type(args[-1]) != type(''): 0460 args, func = args[:-1], args[-1] 0461 for arg in args: 0462 if arg: 0463 cmd = cmd + (' ' + arg) 0464 self.retrlines(cmd, func) 0465 0466 def rename(self, fromname, toname): 0467 '''Rename a file.''' 0468 resp = self.sendcmd('RNFR ' + fromname) 0469 if resp[0] != '3': 0470 raise error_reply, resp 0471 return self.voidcmd('RNTO ' + toname) 0472 0473 def delete(self, filename): 0474 '''Delete a file.''' 0475 resp = self.sendcmd('DELE ' + filename) 0476 if resp[:3] in ('250', '200'): 0477 return resp 0478 elif resp[:1] == '5': 0479 raise error_perm, resp 0480 else: 0481 raise error_reply, resp 0482 0483 def cwd(self, dirname): 0484 '''Change to a directory.''' 0485 if dirname == '..': 0486 try: 0487 return self.voidcmd('CDUP') 0488 except error_perm, msg: 0489 if msg.args[0][:3] != '500': 0490 raise 0491 elif dirname == '': 0492 dirname = '.' # does nothing, but could return error 0493 cmd = 'CWD ' + dirname 0494 return self.voidcmd(cmd) 0495 0496 def size(self, filename): 0497 '''Retrieve the size of a file.''' 0498 # Note that the RFC doesn't say anything about 'SIZE' 0499 resp = self.sendcmd('SIZE ' + filename) 0500 if resp[:3] == '213': 0501 s = resp[3:].strip() 0502 try: 0503 return int(s) 0504 except (OverflowError, ValueError): 0505 return long(s) 0506 0507 def mkd(self, dirname): 0508 '''Make a directory, return its full pathname.''' 0509 resp = self.sendcmd('MKD ' + dirname) 0510 return parse257(resp) 0511 0512 def rmd(self, dirname): 0513 '''Remove a directory.''' 0514 return self.voidcmd('RMD ' + dirname) 0515 0516 def pwd(self): 0517 '''Return current working directory.''' 0518 resp = self.sendcmd('PWD') 0519 return parse257(resp) 0520 0521 def quit(self): 0522 '''Quit, and close the connection.''' 0523 resp = self.voidcmd('QUIT') 0524 self.close() 0525 return resp 0526 0527 def close(self): 0528 '''Close the connection without assuming anything about it.''' 0529 if self.file: 0530 self.file.close() 0531 self.sock.close() 0532 self.file = self.sock = None 0533 0534 0535 _150_re = None 0536 0537 def parse150(resp): 0538 '''Parse the '150' response for a RETR request. 0539 Returns the expected transfer size or None; size is not guaranteed to 0540 be present in the 150 message. 0541 ''' 0542 if resp[:3] != '150': 0543 raise error_reply, resp 0544 global _150_re 0545 if _150_re is None: 0546 import re 0547 _150_re = re.compile("150 .* \((\d+) bytes\)", re.IGNORECASE) 0548 m = _150_re.match(resp) 0549 if not m: 0550 return None 0551 s = m.group(1) 0552 try: 0553 return int(s) 0554 except (OverflowError, ValueError): 0555 return long(s) 0556 0557 0558 _227_re = None 0559 0560 def parse227(resp): 0561 '''Parse the '227' response for a PASV request. 0562 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)' 0563 Return ('host.addr.as.numbers', port#) tuple.''' 0564 0565 if resp[:3] != '227': 0566 raise error_reply, resp 0567 global _227_re 0568 if _227_re is None: 0569 import re 0570 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)') 0571 m = _227_re.search(resp) 0572 if not m: 0573 raise error_proto, resp 0574 numbers = m.groups() 0575 host = '.'.join(numbers[:4]) 0576 port = (int(numbers[4]) << 8) + int(numbers[5]) 0577 return host, port 0578 0579 0580 def parse229(resp, peer): 0581 '''Parse the '229' response for a EPSV request. 0582 Raises error_proto if it does not contain '(|||port|)' 0583 Return ('host.addr.as.numbers', port#) tuple.''' 0584 0585 if resp[:3] <> '229': 0586 raise error_reply, resp 0587 left = resp.find('(') 0588 if left < 0: raise error_proto, resp 0589 right = resp.find(')', left + 1) 0590 if right < 0: 0591 raise error_proto, resp # should contain '(|||port|)' 0592 if resp[left + 1] <> resp[right - 1]: 0593 raise error_proto, resp 0594 parts = resp[left + 1:right].split(resp[left+1]) 0595 if len(parts) <> 5: 0596 raise error_proto, resp 0597 host = peer[0] 0598 port = int(parts[3]) 0599 return host, port 0600 0601 0602 def parse257(resp): 0603 '''Parse the '257' response for a MKD or PWD request. 0604 This is a response to a MKD or PWD request: a directory name. 0605 Returns the directoryname in the 257 reply.''' 0606 0607 if resp[:3] != '257': 0608 raise error_reply, resp 0609 if resp[3:5] != ' "': 0610 return '' # Not compliant to RFC 959, but UNIX ftpd does this 0611 dirname = '' 0612 i = 5 0613 n = len(resp) 0614 while i < n: 0615 c = resp[i] 0616 i = i+1 0617 if c == '"': 0618 if i >= n or resp[i] != '"': 0619 break 0620 i = i+1 0621 dirname = dirname + c 0622 return dirname 0623 0624 0625 def print_line(line): 0626 '''Default retrlines callback to print a line.''' 0627 print line 0628 0629 0630 def ftpcp(source, sourcename, target, targetname = '', type = 'I'): 0631 '''Copy file from one FTP-instance to another.''' 0632 if not targetname: targetname = sourcename 0633 type = 'TYPE ' + type 0634 source.voidcmd(type) 0635 target.voidcmd(type) 0636 sourcehost, sourceport = parse227(source.sendcmd('PASV')) 0637 target.sendport(sourcehost, sourceport) 0638 # RFC 959: the user must "listen" [...] BEFORE sending the 0639 # transfer request. 0640 # So: STOR before RETR, because here the target is a "user". 0641 treply = target.sendcmd('STOR ' + targetname) 0642 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959 0643 sreply = source.sendcmd('RETR ' + sourcename) 0644 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959 0645 source.voidresp() 0646 target.voidresp() 0647 0648 0649 class Netrc: 0650 """Class to parse & provide access to 'netrc' format files. 0651 0652 See the netrc(4) man page for information on the file format. 0653 0654 WARNING: This class is obsolete -- use module netrc instead. 0655 0656 """ 0657 __defuser = None 0658 __defpasswd = None 0659 __defacct = None 0660 0661 def __init__(self, filename=None): 0662 if filename is None: 0663 if "HOME" in os.environ: 0664 filename = os.path.join(os.environ["HOME"], 0665 ".netrc") 0666 else: 0667 raise IOError, \ 0668 "specify file to load or set $HOME" 0669 self.__hosts = {} 0670 self.__macros = {} 0671 fp = open(filename, "r") 0672 in_macro = 0 0673 while 1: 0674 line = fp.readline() 0675 if not line: break 0676 if in_macro and line.strip(): 0677 macro_lines.append(line) 0678 continue 0679 elif in_macro: 0680 self.__macros[macro_name] = tuple(macro_lines) 0681 in_macro = 0 0682 words = line.split() 0683 host = user = passwd = acct = None 0684 default = 0 0685 i = 0 0686 while i < len(words): 0687 w1 = words[i] 0688 if i+1 < len(words): 0689 w2 = words[i + 1] 0690 else: 0691 w2 = None 0692 if w1 == 'default': 0693 default = 1 0694 elif w1 == 'machine' and w2: 0695 host = w2.lower() 0696 i = i + 1 0697 elif w1 == 'login' and w2: 0698 user = w2 0699 i = i + 1 0700 elif w1 == 'password' and w2: 0701 passwd = w2 0702 i = i + 1 0703 elif w1 == 'account' and w2: 0704 acct = w2 0705 i = i + 1 0706 elif w1 == 'macdef' and w2: 0707 macro_name = w2 0708 macro_lines = [] 0709 in_macro = 1 0710 break 0711 i = i + 1 0712 if default: 0713 self.__defuser = user or self.__defuser 0714 self.__defpasswd = passwd or self.__defpasswd 0715 self.__defacct = acct or self.__defacct 0716 if host: 0717 if host in self.__hosts: 0718 ouser, opasswd, oacct = \ 0719 self.__hosts[host] 0720 user = user or ouser 0721 passwd = passwd or opasswd 0722 acct = acct or oacct 0723 self.__hosts[host] = user, passwd, acct 0724 fp.close() 0725 0726 def get_hosts(self): 0727 """Return a list of hosts mentioned in the .netrc file.""" 0728 return self.__hosts.keys() 0729 0730 def get_account(self, host): 0731 """Returns login information for the named host. 0732 0733 The return value is a triple containing userid, 0734 password, and the accounting field. 0735 0736 """ 0737 host = host.lower() 0738 user = passwd = acct = None 0739 if host in self.__hosts: 0740 user, passwd, acct = self.__hosts[host] 0741 user = user or self.__defuser 0742 passwd = passwd or self.__defpasswd 0743 acct = acct or self.__defacct 0744 return user, passwd, acct 0745 0746 def get_macros(self): 0747 """Return a list of all defined macro names.""" 0748 return self.__macros.keys() 0749 0750 def get_macro(self, macro): 0751 """Return a sequence of lines which define a named macro.""" 0752 return self.__macros[macro] 0753 0754 0755 0756 def test(): 0757 '''Test program. 0758 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...''' 0759 0760 debugging = 0 0761 rcfile = None 0762 while sys.argv[1] == '-d': 0763 debugging = debugging+1 0764 del sys.argv[1] 0765 if sys.argv[1][:2] == '-r': 0766 # get name of alternate ~/.netrc file: 0767 rcfile = sys.argv[1][2:] 0768 del sys.argv[1] 0769 host = sys.argv[1] 0770 ftp = FTP(host) 0771 ftp.set_debuglevel(debugging) 0772 userid = passwd = acct = '' 0773 try: 0774 netrc = Netrc(rcfile) 0775 except IOError: 0776 if rcfile is not None: 0777 sys.stderr.write("Could not open account file" 0778 " -- using anonymous login.") 0779 else: 0780 try: 0781 userid, passwd, acct = netrc.get_account(host) 0782 except KeyError: 0783 # no account for host 0784 sys.stderr.write( 0785 "No account -- using anonymous login.") 0786 ftp.login(userid, passwd, acct) 0787 for file in sys.argv[2:]: 0788 if file[:2] == '-l': 0789 ftp.dir(file[2:]) 0790 elif file[:2] == '-d': 0791 cmd = 'CWD' 0792 if file[2:]: cmd = cmd + ' ' + file[2:] 0793 resp = ftp.sendcmd(cmd) 0794 elif file == '-p': 0795 ftp.set_pasv(not ftp.passiveserver) 0796 else: 0797 ftp.retrbinary('RETR ' + file, \ 0798 sys.stdout.write, 1024) 0799 ftp.quit() 0800 0801 0802 if __name__ == '__main__': 0803 test() 0804
Generated by PyXR 0.9.4