PyXR

c:\python24\lib \ ftplib.py



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
SourceForge.net Logo