blob: 13e1e8a2a2aab8dd4cb2cf84f9f04a945c38d6fa [file] [log] [blame]
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +00001"""An FTP client class and some helper functions.
2
Barry Warsaw100d81e2000-09-01 06:09:23 +00003Based on RFC 959: File Transfer Protocol (FTP), by J. Postel and J. Reynolds
Guido van Rossum1115ab21992-11-04 15:51:30 +00004
Guido van Rossumd2560b01996-05-28 23:41:25 +00005Example:
6
7>>> from ftplib import FTP
8>>> ftp = FTP('ftp.python.org') # connect to host, default port
Guido van Rossum24a64342001-12-28 20:54:55 +00009>>> ftp.login() # default, i.e.: user anonymous, passwd anonymous@
Guido van Rossum2f3941d1997-10-07 14:49:56 +000010'230 Guest login ok, access restrictions apply.'
Guido van Rossumd2560b01996-05-28 23:41:25 +000011>>> ftp.retrlines('LIST') # list directory contents
12total 9
13drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
14drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
15drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
16drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
17d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
18drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
19drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
20drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
21-rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
Guido van Rossum2f3941d1997-10-07 14:49:56 +000022'226 Transfer complete.'
Guido van Rossumd2560b01996-05-28 23:41:25 +000023>>> ftp.quit()
Guido van Rossum2f3941d1997-10-07 14:49:56 +000024'221 Goodbye.'
Tim Peters88869f92001-01-14 23:36:06 +000025>>>
Guido van Rossumd2560b01996-05-28 23:41:25 +000026
27A nice test that reveals some of the network dialogue would be:
28python ftplib.py -d localhost -l -p -l
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000029"""
Guido van Rossumc567c601992-11-05 22:22:37 +000030
Tim Peters88869f92001-01-14 23:36:06 +000031#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000032# 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.
Christian Heimes1af737c2008-01-23 08:24:23 +000035# Modified by Phil Schwartz to add storbinary and storlines callbacks.
Antoine Pitrouf988cd02009-11-17 20:21:14 +000036# Modified by Giampaolo Rodola' to add TLS support.
Guido van Rossum98d9fd32000-02-28 15:12:25 +000037#
Guido van Rossumc567c601992-11-05 22:22:37 +000038
Guido van Rossum1115ab21992-11-04 15:51:30 +000039import os
40import sys
Guido van Rossum1115ab21992-11-04 15:51:30 +000041
Guido van Rossumb6775db1994-08-01 11:34:53 +000042# Import SOCKS module if it exists, else standard socket module socket
43try:
Tim Peters88869f92001-01-14 23:36:06 +000044 import SOCKS; socket = SOCKS; del SOCKS # import SOCKS as socket
45 from socket import getfqdn; socket.getfqdn = getfqdn; del getfqdn
Guido van Rossumb6775db1994-08-01 11:34:53 +000046except ImportError:
Tim Peters88869f92001-01-14 23:36:06 +000047 import socket
Georg Brandlf78e02b2008-06-10 17:40:04 +000048from socket import _GLOBAL_DEFAULT_TIMEOUT
Guido van Rossumb6775db1994-08-01 11:34:53 +000049
Skip Montanaroeccd02a2001-01-20 23:34:12 +000050__all__ = ["FTP","Netrc"]
Guido van Rossum1115ab21992-11-04 15:51:30 +000051
Guido van Rossumd3166071993-05-24 14:16:22 +000052# Magic number from <socket.h>
Tim Peters88869f92001-01-14 23:36:06 +000053MSG_OOB = 0x1 # Process data out of band
Guido van Rossumd3166071993-05-24 14:16:22 +000054
55
Guido van Rossumc567c601992-11-05 22:22:37 +000056# The standard FTP server control port
Guido van Rossum1115ab21992-11-04 15:51:30 +000057FTP_PORT = 21
Guido van Rossum1115ab21992-11-04 15:51:30 +000058
59
Guido van Rossum21974791992-11-06 13:34:17 +000060# Exception raised when an error or invalid response is received
Fred Drake227b1202000-08-17 05:06:49 +000061class Error(Exception): pass
Tim Peters88869f92001-01-14 23:36:06 +000062class error_reply(Error): pass # unexpected [123]xx reply
63class error_temp(Error): pass # 4xx errors
64class error_perm(Error): pass # 5xx errors
65class error_proto(Error): pass # response does not begin with [1-5]
Guido van Rossum1115ab21992-11-04 15:51:30 +000066
67
Guido van Rossum21974791992-11-06 13:34:17 +000068# All exceptions (hopefully) that may be raised here and that aren't
69# (always) programming errors on our side
Christian Heimes33fe8092008-04-13 13:53:33 +000070all_errors = (Error, IOError, EOFError)
Guido van Rossum21974791992-11-06 13:34:17 +000071
72
Guido van Rossum1115ab21992-11-04 15:51:30 +000073# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
74CRLF = '\r\n'
Benjamin Petersonbe17a112008-09-27 21:49:47 +000075B_CRLF = b'\r\n'
Guido van Rossum1115ab21992-11-04 15:51:30 +000076
Guido van Rossum1115ab21992-11-04 15:51:30 +000077# The class itself
78class FTP:
79
Tim Peters88869f92001-01-14 23:36:06 +000080 '''An FTP client class.
Guido van Rossumd2560b01996-05-28 23:41:25 +000081
Guido van Rossumd8faa362007-04-27 19:54:29 +000082 To create a connection, call the class using these arguments:
83 host, user, passwd, acct, timeout
84
85 The first four arguments are all strings, and have default value ''.
86 timeout must be numeric and defaults to None if not passed,
87 meaning that no timeout will be set on any ftp socket(s)
88 If a timeout is passed, then this is now the default timeout for all ftp
89 socket operations for this instance.
90
Tim Peters88869f92001-01-14 23:36:06 +000091 Then use self.connect() with optional host and port argument.
Guido van Rossumd2560b01996-05-28 23:41:25 +000092
Tim Peters88869f92001-01-14 23:36:06 +000093 To download a file, use ftp.retrlines('RETR ' + filename),
94 or ftp.retrbinary() with slightly different arguments.
95 To upload a file, use ftp.storlines() or ftp.storbinary(),
96 which have an open file as argument (see their definitions
97 below for details).
98 The download/upload functions first issue appropriate TYPE
99 and PORT or PASV commands.
Guido van Rossum52b89762007-07-17 20:45:57 +0000100 '''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000101
Fred Drake9c98a422001-02-28 21:46:37 +0000102 debugging = 0
103 host = ''
104 port = FTP_PORT
105 sock = None
106 file = None
107 welcome = None
108 passiveserver = 1
Brett Cannon6733d702007-10-08 19:48:15 +0000109 encoding = "latin1"
Fred Drake9c98a422001-02-28 21:46:37 +0000110
Tim Peters88869f92001-01-14 23:36:06 +0000111 # Initialization method (called by class instantiation).
112 # Initialize host to localhost, port to standard ftp port
113 # Optional arguments are host (for connect()),
114 # and user, passwd, acct (for login())
Georg Brandlf78e02b2008-06-10 17:40:04 +0000115 def __init__(self, host='', user='', passwd='', acct='',
116 timeout=_GLOBAL_DEFAULT_TIMEOUT):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000117 self.timeout = timeout
Tim Peters88869f92001-01-14 23:36:06 +0000118 if host:
Fred Drake9c98a422001-02-28 21:46:37 +0000119 self.connect(host)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000120 if user:
121 self.login(user, passwd, acct)
Guido van Rossum52fc1f61993-06-17 12:38:10 +0000122
Georg Brandlf78e02b2008-06-10 17:40:04 +0000123 def connect(self, host='', port=0, timeout=-999):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000124 '''Connect to host. Arguments are:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000125 - host: hostname to connect to (string, default previous host)
126 - port: port to connect to (integer, default previous port)
127 '''
128 if host != '':
129 self.host = host
130 if port > 0:
131 self.port = port
Georg Brandlf78e02b2008-06-10 17:40:04 +0000132 if timeout != -999:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000133 self.timeout = timeout
134 self.sock = socket.create_connection((self.host, self.port), self.timeout)
135 self.af = self.sock.family
Guido van Rossum52b89762007-07-17 20:45:57 +0000136 self.file = self.sock.makefile('r', encoding=self.encoding)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000137 self.welcome = self.getresp()
138 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000139
Tim Peters88869f92001-01-14 23:36:06 +0000140 def getwelcome(self):
141 '''Get the welcome message from the server.
142 (this is read and squirreled away by connect())'''
143 if self.debugging:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000144 print('*welcome*', self.sanitize(self.welcome))
Tim Peters88869f92001-01-14 23:36:06 +0000145 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000146
Tim Peters88869f92001-01-14 23:36:06 +0000147 def set_debuglevel(self, level):
148 '''Set the debugging level.
149 The required argument level means:
150 0: no debugging output (default)
151 1: print commands and responses but not body text etc.
152 2: also print raw lines read and sent before stripping CR/LF'''
153 self.debugging = level
154 debug = set_debuglevel
Guido van Rossum1115ab21992-11-04 15:51:30 +0000155
Tim Peters88869f92001-01-14 23:36:06 +0000156 def set_pasv(self, val):
157 '''Use passive or active mode for data transfers.
158 With a false argument, use the normal PORT mode,
159 With a true argument, use the PASV command.'''
160 self.passiveserver = val
Guido van Rossumd2560b01996-05-28 23:41:25 +0000161
Tim Peters88869f92001-01-14 23:36:06 +0000162 # Internal: "sanitize" a string for printing
163 def sanitize(self, s):
164 if s[:5] == 'pass ' or s[:5] == 'PASS ':
165 i = len(s)
166 while i > 5 and s[i-1] in '\r\n':
167 i = i-1
168 s = s[:5] + '*'*(i-5) + s[i:]
Walter Dörwald70a6b492004-02-12 17:35:32 +0000169 return repr(s)
Guido van Rossumebaf1041995-05-05 15:54:14 +0000170
Tim Peters88869f92001-01-14 23:36:06 +0000171 # Internal: send one line to the server, appending CRLF
172 def putline(self, line):
173 line = line + CRLF
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000174 if self.debugging > 1: print('*put*', self.sanitize(line))
Guido van Rossum52b89762007-07-17 20:45:57 +0000175 self.sock.sendall(line.encode(self.encoding))
Guido van Rossum1115ab21992-11-04 15:51:30 +0000176
Tim Peters88869f92001-01-14 23:36:06 +0000177 # Internal: send one command to the server (through putline())
178 def putcmd(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000179 if self.debugging: print('*cmd*', self.sanitize(line))
Tim Peters88869f92001-01-14 23:36:06 +0000180 self.putline(line)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000181
Tim Peters88869f92001-01-14 23:36:06 +0000182 # Internal: return one line from the server, stripping CRLF.
183 # Raise EOFError if the connection is closed
184 def getline(self):
185 line = self.file.readline()
186 if self.debugging > 1:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000187 print('*get*', self.sanitize(line))
Tim Peters88869f92001-01-14 23:36:06 +0000188 if not line: raise EOFError
189 if line[-2:] == CRLF: line = line[:-2]
190 elif line[-1:] in CRLF: line = line[:-1]
191 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000192
Tim Peters88869f92001-01-14 23:36:06 +0000193 # Internal: get a response from the server, which may possibly
194 # consist of multiple lines. Return a single string with no
195 # trailing CRLF. If the response consists of multiple lines,
196 # these are separated by '\n' characters in the string
197 def getmultiline(self):
198 line = self.getline()
199 if line[3:4] == '-':
200 code = line[:3]
201 while 1:
202 nextline = self.getline()
203 line = line + ('\n' + nextline)
204 if nextline[:3] == code and \
205 nextline[3:4] != '-':
206 break
207 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000208
Tim Peters88869f92001-01-14 23:36:06 +0000209 # Internal: get a response from the server.
210 # Raise various errors if the response indicates an error
211 def getresp(self):
212 resp = self.getmultiline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000213 if self.debugging: print('*resp*', self.sanitize(resp))
Tim Peters88869f92001-01-14 23:36:06 +0000214 self.lastresp = resp[:3]
215 c = resp[:1]
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000216 if c in ('1', '2', '3'):
217 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000218 if c == '4':
Collin Winterce36ad82007-08-30 01:19:48 +0000219 raise error_temp(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000220 if c == '5':
Collin Winterce36ad82007-08-30 01:19:48 +0000221 raise error_perm(resp)
222 raise error_proto(resp)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000223
Tim Peters88869f92001-01-14 23:36:06 +0000224 def voidresp(self):
225 """Expect a response beginning with '2'."""
226 resp = self.getresp()
Benjamin Petersond23f8222009-04-05 19:13:16 +0000227 if resp[:1] != '2':
Collin Winterce36ad82007-08-30 01:19:48 +0000228 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000229 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000230
Tim Peters88869f92001-01-14 23:36:06 +0000231 def abort(self):
232 '''Abort a file transfer. Uses out-of-band data.
233 This does not follow the procedure from the RFC to send Telnet
234 IP and Synch; that doesn't seem to work with the servers I've
235 tried. Instead, just send the ABOR command as OOB data.'''
236 line = 'ABOR' + CRLF
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000237 if self.debugging > 1: print('*put urgent*', self.sanitize(line))
Martin v. Löwise12454f2002-02-16 23:06:19 +0000238 self.sock.sendall(line, MSG_OOB)
Tim Peters88869f92001-01-14 23:36:06 +0000239 resp = self.getmultiline()
240 if resp[:3] not in ('426', '226'):
Collin Winterce36ad82007-08-30 01:19:48 +0000241 raise error_proto(resp)
Guido van Rossumd3166071993-05-24 14:16:22 +0000242
Tim Peters88869f92001-01-14 23:36:06 +0000243 def sendcmd(self, cmd):
244 '''Send a command and return the response.'''
245 self.putcmd(cmd)
246 return self.getresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000247
Tim Peters88869f92001-01-14 23:36:06 +0000248 def voidcmd(self, cmd):
249 """Send a command and expect a response beginning with '2'."""
250 self.putcmd(cmd)
251 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000252
Tim Peters88869f92001-01-14 23:36:06 +0000253 def sendport(self, host, port):
254 '''Send a PORT command with the current host and the given
255 port number.
256 '''
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000257 hbytes = host.split('.')
Benjamin Peterson3a53fbb2008-09-27 22:04:16 +0000258 pbytes = [repr(port//256), repr(port%256)]
Tim Peters88869f92001-01-14 23:36:06 +0000259 bytes = hbytes + pbytes
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000260 cmd = 'PORT ' + ','.join(bytes)
Tim Peters88869f92001-01-14 23:36:06 +0000261 return self.voidcmd(cmd)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000262
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000263 def sendeprt(self, host, port):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000264 '''Send a EPRT command with the current host and the given port number.'''
265 af = 0
266 if self.af == socket.AF_INET:
267 af = 1
268 if self.af == socket.AF_INET6:
269 af = 2
270 if af == 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000271 raise error_proto('unsupported address family')
Walter Dörwald70a6b492004-02-12 17:35:32 +0000272 fields = ['', repr(af), host, repr(port), '']
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000273 cmd = 'EPRT ' + '|'.join(fields)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000274 return self.voidcmd(cmd)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000275
Tim Peters88869f92001-01-14 23:36:06 +0000276 def makeport(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000277 '''Create a new socket and send a PORT command for it.'''
Martin v. Löwis2ad25692001-07-31 08:40:21 +0000278 msg = "getaddrinfo returns an empty list"
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000279 sock = None
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000280 for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
281 af, socktype, proto, canonname, sa = res
282 try:
283 sock = socket.socket(af, socktype, proto)
284 sock.bind(sa)
Guido van Rossumb940e112007-01-10 16:19:56 +0000285 except socket.error as msg:
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000286 if sock:
287 sock.close()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000288 sock = None
289 continue
290 break
291 if not sock:
Collin Winterce36ad82007-08-30 01:19:48 +0000292 raise socket.error(msg)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000293 sock.listen(1)
294 port = sock.getsockname()[1] # Get proper port
295 host = self.sock.getsockname()[0] # Get proper host
296 if self.af == socket.AF_INET:
297 resp = self.sendport(host, port)
298 else:
299 resp = self.sendeprt(host, port)
300 return sock
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000301
302 def makepasv(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000303 if self.af == socket.AF_INET:
304 host, port = parse227(self.sendcmd('PASV'))
305 else:
306 host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
307 return host, port
Guido van Rossum1115ab21992-11-04 15:51:30 +0000308
Tim Peters88869f92001-01-14 23:36:06 +0000309 def ntransfercmd(self, cmd, rest=None):
310 """Initiate a transfer over the data connection.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000311
Tim Peters88869f92001-01-14 23:36:06 +0000312 If the transfer is active, send a port command and the
313 transfer command, and accept the connection. If the server is
314 passive, send a pasv command, connect to it, and start the
315 transfer command. Either way, return the socket for the
316 connection and the expected size of the transfer. The
317 expected size may be None if it could not be determined.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000318
Tim Peters88869f92001-01-14 23:36:06 +0000319 Optional `rest' argument can be a string that is sent as the
Christian Heimes1af737c2008-01-23 08:24:23 +0000320 argument to a REST command. This is essentially a server
Tim Peters88869f92001-01-14 23:36:06 +0000321 marker used to tell the server to skip over any data up to the
322 given marker.
323 """
324 size = None
325 if self.passiveserver:
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000326 host, port = self.makepasv()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000327 conn = socket.create_connection((host, port), self.timeout)
Tim Peters88869f92001-01-14 23:36:06 +0000328 if rest is not None:
329 self.sendcmd("REST %s" % rest)
330 resp = self.sendcmd(cmd)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000331 # Some servers apparently send a 200 reply to
332 # a LIST or STOR command, before the 150 reply
333 # (and way before the 226 reply). This seems to
334 # be in violation of the protocol (which only allows
335 # 1xx or error messages for LIST), so we just discard
336 # this response.
337 if resp[0] == '2':
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000338 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000339 if resp[0] != '1':
Collin Winterce36ad82007-08-30 01:19:48 +0000340 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000341 else:
342 sock = self.makeport()
343 if rest is not None:
344 self.sendcmd("REST %s" % rest)
345 resp = self.sendcmd(cmd)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000346 # See above.
347 if resp[0] == '2':
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000348 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000349 if resp[0] != '1':
Collin Winterce36ad82007-08-30 01:19:48 +0000350 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000351 conn, sockaddr = sock.accept()
352 if resp[:3] == '150':
353 # this is conditional in case we received a 125
354 size = parse150(resp)
355 return conn, size
Fred Drake4de02d91997-01-10 18:26:09 +0000356
Tim Peters88869f92001-01-14 23:36:06 +0000357 def transfercmd(self, cmd, rest=None):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000358 """Like ntransfercmd() but returns only the socket."""
Tim Peters88869f92001-01-14 23:36:06 +0000359 return self.ntransfercmd(cmd, rest)[0]
Guido van Rossumc567c601992-11-05 22:22:37 +0000360
Tim Peters88869f92001-01-14 23:36:06 +0000361 def login(self, user = '', passwd = '', acct = ''):
362 '''Login, default anonymous.'''
363 if not user: user = 'anonymous'
364 if not passwd: passwd = ''
365 if not acct: acct = ''
366 if user == 'anonymous' and passwd in ('', '-'):
Tim Peterse4418602002-02-16 07:34:19 +0000367 # If there is no anonymous ftp password specified
368 # then we'll just use anonymous@
369 # We don't send any other thing because:
370 # - We want to remain anonymous
371 # - We want to stop SPAM
372 # - We don't want to let ftp sites to discriminate by the user,
373 # host or country.
Guido van Rossumc33e0772001-12-28 20:54:28 +0000374 passwd = passwd + 'anonymous@'
Tim Peters88869f92001-01-14 23:36:06 +0000375 resp = self.sendcmd('USER ' + user)
376 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
377 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
378 if resp[0] != '2':
Collin Winterce36ad82007-08-30 01:19:48 +0000379 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000380 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000381
Tim Peters88869f92001-01-14 23:36:06 +0000382 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000383 """Retrieve data in binary mode. A new port is created for you.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000384
Christian Heimes1af737c2008-01-23 08:24:23 +0000385 Args:
386 cmd: A RETR command.
387 callback: A single parameter callable to be called on each
388 block of data read.
389 blocksize: The maximum number of bytes to read from the
390 socket at one time. [default: 8192]
391 rest: Passed to transfercmd(). [default: None]
Guido van Rossum1115ab21992-11-04 15:51:30 +0000392
Christian Heimes1af737c2008-01-23 08:24:23 +0000393 Returns:
394 The response code.
Tim Peters88869f92001-01-14 23:36:06 +0000395 """
396 self.voidcmd('TYPE I')
397 conn = self.transfercmd(cmd, rest)
398 while 1:
399 data = conn.recv(blocksize)
400 if not data:
401 break
402 callback(data)
403 conn.close()
404 return self.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000405
Tim Peters88869f92001-01-14 23:36:06 +0000406 def retrlines(self, cmd, callback = None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000407 """Retrieve data in line mode. A new port is created for you.
408
409 Args:
410 cmd: A RETR, LIST, NLST, or MLSD command.
411 callback: An optional single parameter callable that is called
412 for each line with the trailing CRLF stripped.
413 [default: print_line()]
414
415 Returns:
416 The response code.
417 """
Raymond Hettingere874fc32002-05-12 05:53:51 +0000418 if callback is None: callback = print_line
Tim Peters88869f92001-01-14 23:36:06 +0000419 resp = self.sendcmd('TYPE A')
420 conn = self.transfercmd(cmd)
Guido van Rossum52b89762007-07-17 20:45:57 +0000421 fp = conn.makefile('r', encoding=self.encoding)
Tim Peters88869f92001-01-14 23:36:06 +0000422 while 1:
423 line = fp.readline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000424 if self.debugging > 2: print('*retr*', repr(line))
Tim Peters88869f92001-01-14 23:36:06 +0000425 if not line:
426 break
427 if line[-2:] == CRLF:
428 line = line[:-2]
429 elif line[-1:] == '\n':
430 line = line[:-1]
431 callback(line)
432 fp.close()
433 conn.close()
434 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000435
Christian Heimes1af737c2008-01-23 08:24:23 +0000436 def storbinary(self, cmd, fp, blocksize=8192, callback=None):
437 """Store a file in binary mode. A new port is created for you.
438
439 Args:
440 cmd: A STOR command.
441 fp: A file-like object with a read(num_bytes) method.
442 blocksize: The maximum data size to read from fp and send over
443 the connection at once. [default: 8192]
444 callback: An optional single parameter callable that is called on
445 on each block of data after it is sent. [default: None]
446
447 Returns:
448 The response code.
449 """
Tim Peters88869f92001-01-14 23:36:06 +0000450 self.voidcmd('TYPE I')
451 conn = self.transfercmd(cmd)
452 while 1:
453 buf = fp.read(blocksize)
454 if not buf: break
Martin v. Löwise12454f2002-02-16 23:06:19 +0000455 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000456 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000457 conn.close()
458 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000459
Christian Heimes1af737c2008-01-23 08:24:23 +0000460 def storlines(self, cmd, fp, callback=None):
461 """Store a file in line mode. A new port is created for you.
462
463 Args:
464 cmd: A STOR command.
465 fp: A file-like object with a readline() method.
466 callback: An optional single parameter callable that is called on
467 on each line after it is sent. [default: None]
468
469 Returns:
470 The response code.
471 """
Tim Peters88869f92001-01-14 23:36:06 +0000472 self.voidcmd('TYPE A')
473 conn = self.transfercmd(cmd)
474 while 1:
475 buf = fp.readline()
476 if not buf: break
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000477 if buf[-2:] != B_CRLF:
478 if buf[-1] in B_CRLF: buf = buf[:-1]
479 buf = buf + B_CRLF
Martin v. Löwise12454f2002-02-16 23:06:19 +0000480 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000481 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000482 conn.close()
483 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000484
Tim Peters88869f92001-01-14 23:36:06 +0000485 def acct(self, password):
486 '''Send new account name.'''
487 cmd = 'ACCT ' + password
488 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000489
Tim Peters88869f92001-01-14 23:36:06 +0000490 def nlst(self, *args):
491 '''Return a list of files in a given directory (default the current).'''
492 cmd = 'NLST'
493 for arg in args:
494 cmd = cmd + (' ' + arg)
495 files = []
496 self.retrlines(cmd, files.append)
497 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000498
Tim Peters88869f92001-01-14 23:36:06 +0000499 def dir(self, *args):
500 '''List a directory in long form.
501 By default list current directory to stdout.
502 Optional last argument is callback function; all
503 non-empty arguments before it are concatenated to the
504 LIST command. (This *should* only be used for a pathname.)'''
505 cmd = 'LIST'
506 func = None
507 if args[-1:] and type(args[-1]) != type(''):
508 args, func = args[:-1], args[-1]
509 for arg in args:
510 if arg:
511 cmd = cmd + (' ' + arg)
512 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000513
Tim Peters88869f92001-01-14 23:36:06 +0000514 def rename(self, fromname, toname):
515 '''Rename a file.'''
516 resp = self.sendcmd('RNFR ' + fromname)
517 if resp[0] != '3':
Collin Winterce36ad82007-08-30 01:19:48 +0000518 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000519 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000520
Tim Peters88869f92001-01-14 23:36:06 +0000521 def delete(self, filename):
522 '''Delete a file.'''
523 resp = self.sendcmd('DELE ' + filename)
524 if resp[:3] in ('250', '200'):
525 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000526 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000527 raise error_reply(resp)
Guido van Rossum02cf5821993-05-17 08:00:02 +0000528
Tim Peters88869f92001-01-14 23:36:06 +0000529 def cwd(self, dirname):
530 '''Change to a directory.'''
531 if dirname == '..':
532 try:
533 return self.voidcmd('CDUP')
Guido van Rossumb940e112007-01-10 16:19:56 +0000534 except error_perm as msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000535 if msg.args[0][:3] != '500':
536 raise
Tim Peters88869f92001-01-14 23:36:06 +0000537 elif dirname == '':
538 dirname = '.' # does nothing, but could return error
539 cmd = 'CWD ' + dirname
540 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000541
Tim Peters88869f92001-01-14 23:36:06 +0000542 def size(self, filename):
543 '''Retrieve the size of a file.'''
Christian Heimes1af737c2008-01-23 08:24:23 +0000544 # The SIZE command is defined in RFC-3659
Tim Peters88869f92001-01-14 23:36:06 +0000545 resp = self.sendcmd('SIZE ' + filename)
546 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000547 s = resp[3:].strip()
548 try:
549 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000550 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000551 return int(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000552
Tim Peters88869f92001-01-14 23:36:06 +0000553 def mkd(self, dirname):
554 '''Make a directory, return its full pathname.'''
555 resp = self.sendcmd('MKD ' + dirname)
556 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000557
Tim Peters88869f92001-01-14 23:36:06 +0000558 def rmd(self, dirname):
559 '''Remove a directory.'''
560 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000561
Tim Peters88869f92001-01-14 23:36:06 +0000562 def pwd(self):
563 '''Return current working directory.'''
564 resp = self.sendcmd('PWD')
565 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000566
Tim Peters88869f92001-01-14 23:36:06 +0000567 def quit(self):
568 '''Quit, and close the connection.'''
569 resp = self.voidcmd('QUIT')
570 self.close()
571 return resp
572
573 def close(self):
574 '''Close the connection without assuming anything about it.'''
Fred Drake9c98a422001-02-28 21:46:37 +0000575 if self.file:
576 self.file.close()
577 self.sock.close()
578 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000579
580
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000581try:
582 import ssl
583except ImportError:
584 pass
585else:
586 class FTP_TLS(FTP):
587 '''A FTP subclass which adds TLS support to FTP as described
588 in RFC-4217.
589
590 Connect as usual to port 21 implicitly securing the FTP control
591 connection before authenticating.
592
593 Securing the data connection requires user to explicitly ask
594 for it by calling prot_p() method.
595
596 Usage example:
597 >>> from ftplib import FTP_TLS
598 >>> ftps = FTP_TLS('ftp.python.org')
599 >>> ftps.login() # login anonimously previously securing control channel
600 '230 Guest login ok, access restrictions apply.'
601 >>> ftps.prot_p() # switch to secure data connection
602 '200 Protection level set to P'
603 >>> ftps.retrlines('LIST') # list directory content securely
604 total 9
605 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
606 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
607 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
608 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
609 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
610 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
611 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
612 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
613 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
614 '226 Transfer complete.'
615 >>> ftps.quit()
616 '221 Goodbye.'
617 >>>
618 '''
619 ssl_version = ssl.PROTOCOL_TLSv1
620
621 def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
622 certfile=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
623 self.keyfile = keyfile
624 self.certfile = certfile
625 self._prot_p = False
626 FTP.__init__(self, host, user, passwd, acct, timeout)
627
628 def login(self, user='', passwd='', acct='', secure=True):
629 if secure and not isinstance(self.sock, ssl.SSLSocket):
630 self.auth()
631 return FTP.login(self, user, passwd, acct)
632
633 def auth(self):
634 '''Set up secure control connection by using TLS/SSL.'''
635 if isinstance(self.sock, ssl.SSLSocket):
636 raise ValueError("Already using TLS")
637 if self.ssl_version == ssl.PROTOCOL_TLSv1:
638 resp = self.voidcmd('AUTH TLS')
639 else:
640 resp = self.voidcmd('AUTH SSL')
641 self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile,
642 ssl_version=self.ssl_version)
643 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
644 return resp
645
646 def prot_p(self):
647 '''Set up secure data connection.'''
648 # PROT defines whether or not the data channel is to be protected.
649 # Though RFC-2228 defines four possible protection levels,
650 # RFC-4217 only recommends two, Clear and Private.
651 # Clear (PROT C) means that no security is to be used on the
652 # data-channel, Private (PROT P) means that the data-channel
653 # should be protected by TLS.
654 # PBSZ command MUST still be issued, but must have a parameter of
655 # '0' to indicate that no buffering is taking place and the data
656 # connection should not be encapsulated.
657 self.voidcmd('PBSZ 0')
658 resp = self.voidcmd('PROT P')
659 self._prot_p = True
660 return resp
661
662 def prot_c(self):
663 '''Set up clear text data connection.'''
664 resp = self.voidcmd('PROT C')
665 self._prot_p = False
666 return resp
667
668 # --- Overridden FTP methods
669
670 def ntransfercmd(self, cmd, rest=None):
671 conn, size = FTP.ntransfercmd(self, cmd, rest)
672 if self._prot_p:
673 conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
674 ssl_version=self.ssl_version)
675 return conn, size
676
677 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
678 self.voidcmd('TYPE I')
679 conn = self.transfercmd(cmd, rest)
680 try:
681 while 1:
682 data = conn.recv(blocksize)
683 if not data:
684 break
685 callback(data)
686 # shutdown ssl layer
687 if isinstance(conn, ssl.SSLSocket):
688 conn.unwrap()
689 finally:
690 conn.close()
691 return self.voidresp()
692
693 def retrlines(self, cmd, callback = None):
694 if callback is None: callback = print_line
695 resp = self.sendcmd('TYPE A')
696 conn = self.transfercmd(cmd)
697 fp = conn.makefile('r', encoding=self.encoding)
698 try:
699 while 1:
700 line = fp.readline()
701 if self.debugging > 2: print('*retr*', repr(line))
702 if not line:
703 break
704 if line[-2:] == CRLF:
705 line = line[:-2]
706 elif line[-1:] == '\n':
707 line = line[:-1]
708 callback(line)
709 # shutdown ssl layer
710 if isinstance(conn, ssl.SSLSocket):
711 conn.unwrap()
712 finally:
713 fp.close()
714 conn.close()
715 return self.voidresp()
716
717 def storbinary(self, cmd, fp, blocksize=8192, callback=None):
718 self.voidcmd('TYPE I')
719 conn = self.transfercmd(cmd)
720 try:
721 while 1:
722 buf = fp.read(blocksize)
723 if not buf: break
724 conn.sendall(buf)
725 if callback: callback(buf)
726 # shutdown ssl layer
727 if isinstance(conn, ssl.SSLSocket):
728 conn.unwrap()
729 finally:
730 conn.close()
731 return self.voidresp()
732
733 def storlines(self, cmd, fp, callback=None):
734 self.voidcmd('TYPE A')
735 conn = self.transfercmd(cmd)
736 try:
737 while 1:
738 buf = fp.readline()
739 if not buf: break
740 if buf[-2:] != B_CRLF:
741 if buf[-1] in B_CRLF: buf = buf[:-1]
742 buf = buf + B_CRLF
743 conn.sendall(buf)
744 if callback: callback(buf)
745 # shutdown ssl layer
746 if isinstance(conn, ssl.SSLSocket):
747 conn.unwrap()
748 finally:
749 conn.close()
750 return self.voidresp()
751
752 __all__.append('FTP_TLS')
753 all_errors = (Error, IOError, EOFError, ssl.SSLError)
754
755
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000756_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000757
758def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000759 '''Parse the '150' response for a RETR request.
760 Returns the expected transfer size or None; size is not guaranteed to
761 be present in the 150 message.
762 '''
763 if resp[:3] != '150':
Collin Winterce36ad82007-08-30 01:19:48 +0000764 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000765 global _150_re
766 if _150_re is None:
767 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000768 _150_re = re.compile(
769 "150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII)
Tim Peters88869f92001-01-14 23:36:06 +0000770 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000771 if not m:
772 return None
773 s = m.group(1)
774 try:
775 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000776 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000777 return int(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000778
779
Guido van Rossum70297d32001-08-17 17:24:29 +0000780_227_re = None
781
Guido van Rossumd2560b01996-05-28 23:41:25 +0000782def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000783 '''Parse the '227' response for a PASV request.
784 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
785 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000786
Tim Peters88869f92001-01-14 23:36:06 +0000787 if resp[:3] != '227':
Collin Winterce36ad82007-08-30 01:19:48 +0000788 raise error_reply(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000789 global _227_re
790 if _227_re is None:
791 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000792 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII)
Guido van Rossum70297d32001-08-17 17:24:29 +0000793 m = _227_re.search(resp)
794 if not m:
Collin Winterce36ad82007-08-30 01:19:48 +0000795 raise error_proto(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000796 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000797 host = '.'.join(numbers[:4])
798 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000799 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000800
801
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000802def parse229(resp, peer):
803 '''Parse the '229' response for a EPSV request.
804 Raises error_proto if it does not contain '(|||port|)'
805 Return ('host.addr.as.numbers', port#) tuple.'''
806
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000807 if resp[:3] != '229':
Collin Winterce36ad82007-08-30 01:19:48 +0000808 raise error_reply(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000809 left = resp.find('(')
Collin Winterce36ad82007-08-30 01:19:48 +0000810 if left < 0: raise error_proto(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000811 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000812 if right < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000813 raise error_proto(resp) # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000814 if resp[left + 1] != resp[right - 1]:
Collin Winterce36ad82007-08-30 01:19:48 +0000815 raise error_proto(resp)
Walter Dörwalda401ae42002-06-03 10:41:45 +0000816 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000817 if len(parts) != 5:
Collin Winterce36ad82007-08-30 01:19:48 +0000818 raise error_proto(resp)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000819 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000820 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000821 return host, port
822
823
Guido van Rossumc567c601992-11-05 22:22:37 +0000824def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000825 '''Parse the '257' response for a MKD or PWD request.
826 This is a response to a MKD or PWD request: a directory name.
827 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000828
Tim Peters88869f92001-01-14 23:36:06 +0000829 if resp[:3] != '257':
Collin Winterce36ad82007-08-30 01:19:48 +0000830 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000831 if resp[3:5] != ' "':
832 return '' # Not compliant to RFC 959, but UNIX ftpd does this
833 dirname = ''
834 i = 5
835 n = len(resp)
836 while i < n:
837 c = resp[i]
838 i = i+1
839 if c == '"':
840 if i >= n or resp[i] != '"':
841 break
842 i = i+1
843 dirname = dirname + c
844 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000845
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000846
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000847def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000848 '''Default retrlines callback to print a line.'''
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000849 print(line)
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000850
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000851
Guido van Rossumd2560b01996-05-28 23:41:25 +0000852def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000853 '''Copy file from one FTP-instance to another.'''
854 if not targetname: targetname = sourcename
855 type = 'TYPE ' + type
856 source.voidcmd(type)
857 target.voidcmd(type)
858 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
859 target.sendport(sourcehost, sourceport)
860 # RFC 959: the user must "listen" [...] BEFORE sending the
861 # transfer request.
862 # So: STOR before RETR, because here the target is a "user".
863 treply = target.sendcmd('STOR ' + targetname)
864 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
865 sreply = source.sendcmd('RETR ' + sourcename)
866 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
867 source.voidresp()
868 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000869
Tim Peters88869f92001-01-14 23:36:06 +0000870
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000871class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000872 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000873
Tim Peters88869f92001-01-14 23:36:06 +0000874 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000875
Tim Peters88869f92001-01-14 23:36:06 +0000876 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000877
Tim Peters88869f92001-01-14 23:36:06 +0000878 """
879 __defuser = None
880 __defpasswd = None
881 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000882
Tim Peters88869f92001-01-14 23:36:06 +0000883 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000884 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000885 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000886 filename = os.path.join(os.environ["HOME"],
887 ".netrc")
888 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000889 raise IOError("specify file to load or set $HOME")
Tim Peters88869f92001-01-14 23:36:06 +0000890 self.__hosts = {}
891 self.__macros = {}
892 fp = open(filename, "r")
893 in_macro = 0
894 while 1:
895 line = fp.readline()
896 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000897 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000898 macro_lines.append(line)
899 continue
900 elif in_macro:
901 self.__macros[macro_name] = tuple(macro_lines)
902 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000903 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000904 host = user = passwd = acct = None
905 default = 0
906 i = 0
907 while i < len(words):
908 w1 = words[i]
909 if i+1 < len(words):
910 w2 = words[i + 1]
911 else:
912 w2 = None
913 if w1 == 'default':
914 default = 1
915 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000916 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000917 i = i + 1
918 elif w1 == 'login' and w2:
919 user = w2
920 i = i + 1
921 elif w1 == 'password' and w2:
922 passwd = w2
923 i = i + 1
924 elif w1 == 'account' and w2:
925 acct = w2
926 i = i + 1
927 elif w1 == 'macdef' and w2:
928 macro_name = w2
929 macro_lines = []
930 in_macro = 1
931 break
932 i = i + 1
933 if default:
934 self.__defuser = user or self.__defuser
935 self.__defpasswd = passwd or self.__defpasswd
936 self.__defacct = acct or self.__defacct
937 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000938 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000939 ouser, opasswd, oacct = \
940 self.__hosts[host]
941 user = user or ouser
942 passwd = passwd or opasswd
943 acct = acct or oacct
944 self.__hosts[host] = user, passwd, acct
945 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000946
Tim Peters88869f92001-01-14 23:36:06 +0000947 def get_hosts(self):
948 """Return a list of hosts mentioned in the .netrc file."""
949 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000950
Tim Peters88869f92001-01-14 23:36:06 +0000951 def get_account(self, host):
952 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000953
Tim Peters88869f92001-01-14 23:36:06 +0000954 The return value is a triple containing userid,
955 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000956
Tim Peters88869f92001-01-14 23:36:06 +0000957 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000958 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000959 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000960 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000961 user, passwd, acct = self.__hosts[host]
962 user = user or self.__defuser
963 passwd = passwd or self.__defpasswd
964 acct = acct or self.__defacct
965 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +0000966
Tim Peters88869f92001-01-14 23:36:06 +0000967 def get_macros(self):
968 """Return a list of all defined macro names."""
969 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000970
Tim Peters88869f92001-01-14 23:36:06 +0000971 def get_macro(self, macro):
972 """Return a sequence of lines which define a named macro."""
973 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000974
Fred Drake475d51d1997-06-24 22:02:54 +0000975
Tim Peters88869f92001-01-14 23:36:06 +0000976
Guido van Rossum1115ab21992-11-04 15:51:30 +0000977def test():
Tim Peters88869f92001-01-14 23:36:06 +0000978 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000979 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
980
981 -d dir
982 -l list
983 -p password
984 '''
985
986 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000987 print(test.__doc__)
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000988 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +0000989
Tim Peters88869f92001-01-14 23:36:06 +0000990 debugging = 0
991 rcfile = None
992 while sys.argv[1] == '-d':
993 debugging = debugging+1
994 del sys.argv[1]
995 if sys.argv[1][:2] == '-r':
996 # get name of alternate ~/.netrc file:
997 rcfile = sys.argv[1][2:]
998 del sys.argv[1]
999 host = sys.argv[1]
1000 ftp = FTP(host)
1001 ftp.set_debuglevel(debugging)
1002 userid = passwd = acct = ''
1003 try:
1004 netrc = Netrc(rcfile)
1005 except IOError:
1006 if rcfile is not None:
1007 sys.stderr.write("Could not open account file"
1008 " -- using anonymous login.")
1009 else:
1010 try:
1011 userid, passwd, acct = netrc.get_account(host)
1012 except KeyError:
1013 # no account for host
1014 sys.stderr.write(
1015 "No account -- using anonymous login.")
1016 ftp.login(userid, passwd, acct)
1017 for file in sys.argv[2:]:
1018 if file[:2] == '-l':
1019 ftp.dir(file[2:])
1020 elif file[:2] == '-d':
1021 cmd = 'CWD'
1022 if file[2:]: cmd = cmd + ' ' + file[2:]
1023 resp = ftp.sendcmd(cmd)
1024 elif file == '-p':
1025 ftp.set_pasv(not ftp.passiveserver)
1026 else:
1027 ftp.retrbinary('RETR ' + file, \
1028 sys.stdout.write, 1024)
1029 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +00001030
1031
1032if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +00001033 test()