blob: ea3f99617dc8aaa2333a9e8b57d07812e15dc58f [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
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000436 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000437 """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]
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000446 rest: Passed to transfercmd(). [default: None]
Christian Heimes1af737c2008-01-23 08:24:23 +0000447
448 Returns:
449 The response code.
450 """
Tim Peters88869f92001-01-14 23:36:06 +0000451 self.voidcmd('TYPE I')
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000452 conn = self.transfercmd(cmd, rest)
Tim Peters88869f92001-01-14 23:36:06 +0000453 while 1:
454 buf = fp.read(blocksize)
455 if not buf: break
Martin v. Löwise12454f2002-02-16 23:06:19 +0000456 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000457 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000458 conn.close()
459 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000460
Christian Heimes1af737c2008-01-23 08:24:23 +0000461 def storlines(self, cmd, fp, callback=None):
462 """Store a file in line mode. A new port is created for you.
463
464 Args:
465 cmd: A STOR command.
466 fp: A file-like object with a readline() method.
467 callback: An optional single parameter callable that is called on
468 on each line after it is sent. [default: None]
469
470 Returns:
471 The response code.
472 """
Tim Peters88869f92001-01-14 23:36:06 +0000473 self.voidcmd('TYPE A')
474 conn = self.transfercmd(cmd)
475 while 1:
476 buf = fp.readline()
477 if not buf: break
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000478 if buf[-2:] != B_CRLF:
479 if buf[-1] in B_CRLF: buf = buf[:-1]
480 buf = buf + B_CRLF
Martin v. Löwise12454f2002-02-16 23:06:19 +0000481 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000482 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000483 conn.close()
484 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000485
Tim Peters88869f92001-01-14 23:36:06 +0000486 def acct(self, password):
487 '''Send new account name.'''
488 cmd = 'ACCT ' + password
489 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000490
Tim Peters88869f92001-01-14 23:36:06 +0000491 def nlst(self, *args):
492 '''Return a list of files in a given directory (default the current).'''
493 cmd = 'NLST'
494 for arg in args:
495 cmd = cmd + (' ' + arg)
496 files = []
497 self.retrlines(cmd, files.append)
498 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000499
Tim Peters88869f92001-01-14 23:36:06 +0000500 def dir(self, *args):
501 '''List a directory in long form.
502 By default list current directory to stdout.
503 Optional last argument is callback function; all
504 non-empty arguments before it are concatenated to the
505 LIST command. (This *should* only be used for a pathname.)'''
506 cmd = 'LIST'
507 func = None
508 if args[-1:] and type(args[-1]) != type(''):
509 args, func = args[:-1], args[-1]
510 for arg in args:
511 if arg:
512 cmd = cmd + (' ' + arg)
513 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000514
Tim Peters88869f92001-01-14 23:36:06 +0000515 def rename(self, fromname, toname):
516 '''Rename a file.'''
517 resp = self.sendcmd('RNFR ' + fromname)
518 if resp[0] != '3':
Collin Winterce36ad82007-08-30 01:19:48 +0000519 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000520 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000521
Tim Peters88869f92001-01-14 23:36:06 +0000522 def delete(self, filename):
523 '''Delete a file.'''
524 resp = self.sendcmd('DELE ' + filename)
525 if resp[:3] in ('250', '200'):
526 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000527 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000528 raise error_reply(resp)
Guido van Rossum02cf5821993-05-17 08:00:02 +0000529
Tim Peters88869f92001-01-14 23:36:06 +0000530 def cwd(self, dirname):
531 '''Change to a directory.'''
532 if dirname == '..':
533 try:
534 return self.voidcmd('CDUP')
Guido van Rossumb940e112007-01-10 16:19:56 +0000535 except error_perm as msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000536 if msg.args[0][:3] != '500':
537 raise
Tim Peters88869f92001-01-14 23:36:06 +0000538 elif dirname == '':
539 dirname = '.' # does nothing, but could return error
540 cmd = 'CWD ' + dirname
541 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000542
Tim Peters88869f92001-01-14 23:36:06 +0000543 def size(self, filename):
544 '''Retrieve the size of a file.'''
Christian Heimes1af737c2008-01-23 08:24:23 +0000545 # The SIZE command is defined in RFC-3659
Tim Peters88869f92001-01-14 23:36:06 +0000546 resp = self.sendcmd('SIZE ' + filename)
547 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000548 s = resp[3:].strip()
549 try:
550 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000551 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000552 return int(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000553
Tim Peters88869f92001-01-14 23:36:06 +0000554 def mkd(self, dirname):
555 '''Make a directory, return its full pathname.'''
556 resp = self.sendcmd('MKD ' + dirname)
557 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000558
Tim Peters88869f92001-01-14 23:36:06 +0000559 def rmd(self, dirname):
560 '''Remove a directory.'''
561 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000562
Tim Peters88869f92001-01-14 23:36:06 +0000563 def pwd(self):
564 '''Return current working directory.'''
565 resp = self.sendcmd('PWD')
566 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000567
Tim Peters88869f92001-01-14 23:36:06 +0000568 def quit(self):
569 '''Quit, and close the connection.'''
570 resp = self.voidcmd('QUIT')
571 self.close()
572 return resp
573
574 def close(self):
575 '''Close the connection without assuming anything about it.'''
Fred Drake9c98a422001-02-28 21:46:37 +0000576 if self.file:
577 self.file.close()
578 self.sock.close()
579 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000580
581
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000582try:
583 import ssl
584except ImportError:
585 pass
586else:
587 class FTP_TLS(FTP):
588 '''A FTP subclass which adds TLS support to FTP as described
589 in RFC-4217.
590
591 Connect as usual to port 21 implicitly securing the FTP control
592 connection before authenticating.
593
594 Securing the data connection requires user to explicitly ask
595 for it by calling prot_p() method.
596
597 Usage example:
598 >>> from ftplib import FTP_TLS
599 >>> ftps = FTP_TLS('ftp.python.org')
600 >>> ftps.login() # login anonimously previously securing control channel
601 '230 Guest login ok, access restrictions apply.'
602 >>> ftps.prot_p() # switch to secure data connection
603 '200 Protection level set to P'
604 >>> ftps.retrlines('LIST') # list directory content securely
605 total 9
606 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
607 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
608 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
609 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
610 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
611 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
612 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
613 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
614 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
615 '226 Transfer complete.'
616 >>> ftps.quit()
617 '221 Goodbye.'
618 >>>
619 '''
620 ssl_version = ssl.PROTOCOL_TLSv1
621
622 def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
623 certfile=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
624 self.keyfile = keyfile
625 self.certfile = certfile
626 self._prot_p = False
627 FTP.__init__(self, host, user, passwd, acct, timeout)
628
629 def login(self, user='', passwd='', acct='', secure=True):
630 if secure and not isinstance(self.sock, ssl.SSLSocket):
631 self.auth()
632 return FTP.login(self, user, passwd, acct)
633
634 def auth(self):
635 '''Set up secure control connection by using TLS/SSL.'''
636 if isinstance(self.sock, ssl.SSLSocket):
637 raise ValueError("Already using TLS")
638 if self.ssl_version == ssl.PROTOCOL_TLSv1:
639 resp = self.voidcmd('AUTH TLS')
640 else:
641 resp = self.voidcmd('AUTH SSL')
642 self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile,
643 ssl_version=self.ssl_version)
644 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
645 return resp
646
647 def prot_p(self):
648 '''Set up secure data connection.'''
649 # PROT defines whether or not the data channel is to be protected.
650 # Though RFC-2228 defines four possible protection levels,
651 # RFC-4217 only recommends two, Clear and Private.
652 # Clear (PROT C) means that no security is to be used on the
653 # data-channel, Private (PROT P) means that the data-channel
654 # should be protected by TLS.
655 # PBSZ command MUST still be issued, but must have a parameter of
656 # '0' to indicate that no buffering is taking place and the data
657 # connection should not be encapsulated.
658 self.voidcmd('PBSZ 0')
659 resp = self.voidcmd('PROT P')
660 self._prot_p = True
661 return resp
662
663 def prot_c(self):
664 '''Set up clear text data connection.'''
665 resp = self.voidcmd('PROT C')
666 self._prot_p = False
667 return resp
668
669 # --- Overridden FTP methods
670
671 def ntransfercmd(self, cmd, rest=None):
672 conn, size = FTP.ntransfercmd(self, cmd, rest)
673 if self._prot_p:
674 conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
675 ssl_version=self.ssl_version)
676 return conn, size
677
678 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
679 self.voidcmd('TYPE I')
680 conn = self.transfercmd(cmd, rest)
681 try:
682 while 1:
683 data = conn.recv(blocksize)
684 if not data:
685 break
686 callback(data)
687 # shutdown ssl layer
688 if isinstance(conn, ssl.SSLSocket):
689 conn.unwrap()
690 finally:
691 conn.close()
692 return self.voidresp()
693
694 def retrlines(self, cmd, callback = None):
695 if callback is None: callback = print_line
696 resp = self.sendcmd('TYPE A')
697 conn = self.transfercmd(cmd)
698 fp = conn.makefile('r', encoding=self.encoding)
699 try:
700 while 1:
701 line = fp.readline()
702 if self.debugging > 2: print('*retr*', repr(line))
703 if not line:
704 break
705 if line[-2:] == CRLF:
706 line = line[:-2]
707 elif line[-1:] == '\n':
708 line = line[:-1]
709 callback(line)
710 # shutdown ssl layer
711 if isinstance(conn, ssl.SSLSocket):
712 conn.unwrap()
713 finally:
714 fp.close()
715 conn.close()
716 return self.voidresp()
717
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000718 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000719 self.voidcmd('TYPE I')
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000720 conn = self.transfercmd(cmd, rest)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000721 try:
722 while 1:
723 buf = fp.read(blocksize)
724 if not buf: break
725 conn.sendall(buf)
726 if callback: callback(buf)
727 # shutdown ssl layer
728 if isinstance(conn, ssl.SSLSocket):
729 conn.unwrap()
730 finally:
731 conn.close()
732 return self.voidresp()
733
734 def storlines(self, cmd, fp, callback=None):
735 self.voidcmd('TYPE A')
736 conn = self.transfercmd(cmd)
737 try:
738 while 1:
739 buf = fp.readline()
740 if not buf: break
741 if buf[-2:] != B_CRLF:
742 if buf[-1] in B_CRLF: buf = buf[:-1]
743 buf = buf + B_CRLF
744 conn.sendall(buf)
745 if callback: callback(buf)
746 # shutdown ssl layer
747 if isinstance(conn, ssl.SSLSocket):
748 conn.unwrap()
749 finally:
750 conn.close()
751 return self.voidresp()
752
753 __all__.append('FTP_TLS')
754 all_errors = (Error, IOError, EOFError, ssl.SSLError)
755
756
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000757_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000758
759def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000760 '''Parse the '150' response for a RETR request.
761 Returns the expected transfer size or None; size is not guaranteed to
762 be present in the 150 message.
763 '''
764 if resp[:3] != '150':
Collin Winterce36ad82007-08-30 01:19:48 +0000765 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000766 global _150_re
767 if _150_re is None:
768 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000769 _150_re = re.compile(
770 "150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII)
Tim Peters88869f92001-01-14 23:36:06 +0000771 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000772 if not m:
773 return None
774 s = m.group(1)
775 try:
776 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000777 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000778 return int(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000779
780
Guido van Rossum70297d32001-08-17 17:24:29 +0000781_227_re = None
782
Guido van Rossumd2560b01996-05-28 23:41:25 +0000783def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000784 '''Parse the '227' response for a PASV request.
785 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
786 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000787
Tim Peters88869f92001-01-14 23:36:06 +0000788 if resp[:3] != '227':
Collin Winterce36ad82007-08-30 01:19:48 +0000789 raise error_reply(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000790 global _227_re
791 if _227_re is None:
792 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000793 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII)
Guido van Rossum70297d32001-08-17 17:24:29 +0000794 m = _227_re.search(resp)
795 if not m:
Collin Winterce36ad82007-08-30 01:19:48 +0000796 raise error_proto(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000797 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000798 host = '.'.join(numbers[:4])
799 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000800 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000801
802
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000803def parse229(resp, peer):
804 '''Parse the '229' response for a EPSV request.
805 Raises error_proto if it does not contain '(|||port|)'
806 Return ('host.addr.as.numbers', port#) tuple.'''
807
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000808 if resp[:3] != '229':
Collin Winterce36ad82007-08-30 01:19:48 +0000809 raise error_reply(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000810 left = resp.find('(')
Collin Winterce36ad82007-08-30 01:19:48 +0000811 if left < 0: raise error_proto(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000812 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000813 if right < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000814 raise error_proto(resp) # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000815 if resp[left + 1] != resp[right - 1]:
Collin Winterce36ad82007-08-30 01:19:48 +0000816 raise error_proto(resp)
Walter Dörwalda401ae42002-06-03 10:41:45 +0000817 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000818 if len(parts) != 5:
Collin Winterce36ad82007-08-30 01:19:48 +0000819 raise error_proto(resp)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000820 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000821 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000822 return host, port
823
824
Guido van Rossumc567c601992-11-05 22:22:37 +0000825def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000826 '''Parse the '257' response for a MKD or PWD request.
827 This is a response to a MKD or PWD request: a directory name.
828 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000829
Tim Peters88869f92001-01-14 23:36:06 +0000830 if resp[:3] != '257':
Collin Winterce36ad82007-08-30 01:19:48 +0000831 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000832 if resp[3:5] != ' "':
833 return '' # Not compliant to RFC 959, but UNIX ftpd does this
834 dirname = ''
835 i = 5
836 n = len(resp)
837 while i < n:
838 c = resp[i]
839 i = i+1
840 if c == '"':
841 if i >= n or resp[i] != '"':
842 break
843 i = i+1
844 dirname = dirname + c
845 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000846
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000847
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000848def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000849 '''Default retrlines callback to print a line.'''
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000850 print(line)
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000851
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000852
Guido van Rossumd2560b01996-05-28 23:41:25 +0000853def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000854 '''Copy file from one FTP-instance to another.'''
855 if not targetname: targetname = sourcename
856 type = 'TYPE ' + type
857 source.voidcmd(type)
858 target.voidcmd(type)
859 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
860 target.sendport(sourcehost, sourceport)
861 # RFC 959: the user must "listen" [...] BEFORE sending the
862 # transfer request.
863 # So: STOR before RETR, because here the target is a "user".
864 treply = target.sendcmd('STOR ' + targetname)
865 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
866 sreply = source.sendcmd('RETR ' + sourcename)
867 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
868 source.voidresp()
869 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000870
Tim Peters88869f92001-01-14 23:36:06 +0000871
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000872class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000873 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000874
Tim Peters88869f92001-01-14 23:36:06 +0000875 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000876
Tim Peters88869f92001-01-14 23:36:06 +0000877 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000878
Tim Peters88869f92001-01-14 23:36:06 +0000879 """
880 __defuser = None
881 __defpasswd = None
882 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000883
Tim Peters88869f92001-01-14 23:36:06 +0000884 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000885 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000886 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000887 filename = os.path.join(os.environ["HOME"],
888 ".netrc")
889 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000890 raise IOError("specify file to load or set $HOME")
Tim Peters88869f92001-01-14 23:36:06 +0000891 self.__hosts = {}
892 self.__macros = {}
893 fp = open(filename, "r")
894 in_macro = 0
895 while 1:
896 line = fp.readline()
897 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000898 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000899 macro_lines.append(line)
900 continue
901 elif in_macro:
902 self.__macros[macro_name] = tuple(macro_lines)
903 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000904 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000905 host = user = passwd = acct = None
906 default = 0
907 i = 0
908 while i < len(words):
909 w1 = words[i]
910 if i+1 < len(words):
911 w2 = words[i + 1]
912 else:
913 w2 = None
914 if w1 == 'default':
915 default = 1
916 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000917 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000918 i = i + 1
919 elif w1 == 'login' and w2:
920 user = w2
921 i = i + 1
922 elif w1 == 'password' and w2:
923 passwd = w2
924 i = i + 1
925 elif w1 == 'account' and w2:
926 acct = w2
927 i = i + 1
928 elif w1 == 'macdef' and w2:
929 macro_name = w2
930 macro_lines = []
931 in_macro = 1
932 break
933 i = i + 1
934 if default:
935 self.__defuser = user or self.__defuser
936 self.__defpasswd = passwd or self.__defpasswd
937 self.__defacct = acct or self.__defacct
938 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000939 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000940 ouser, opasswd, oacct = \
941 self.__hosts[host]
942 user = user or ouser
943 passwd = passwd or opasswd
944 acct = acct or oacct
945 self.__hosts[host] = user, passwd, acct
946 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000947
Tim Peters88869f92001-01-14 23:36:06 +0000948 def get_hosts(self):
949 """Return a list of hosts mentioned in the .netrc file."""
950 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000951
Tim Peters88869f92001-01-14 23:36:06 +0000952 def get_account(self, host):
953 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000954
Tim Peters88869f92001-01-14 23:36:06 +0000955 The return value is a triple containing userid,
956 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000957
Tim Peters88869f92001-01-14 23:36:06 +0000958 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000959 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000960 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000961 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000962 user, passwd, acct = self.__hosts[host]
963 user = user or self.__defuser
964 passwd = passwd or self.__defpasswd
965 acct = acct or self.__defacct
966 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +0000967
Tim Peters88869f92001-01-14 23:36:06 +0000968 def get_macros(self):
969 """Return a list of all defined macro names."""
970 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000971
Tim Peters88869f92001-01-14 23:36:06 +0000972 def get_macro(self, macro):
973 """Return a sequence of lines which define a named macro."""
974 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000975
Fred Drake475d51d1997-06-24 22:02:54 +0000976
Tim Peters88869f92001-01-14 23:36:06 +0000977
Guido van Rossum1115ab21992-11-04 15:51:30 +0000978def test():
Tim Peters88869f92001-01-14 23:36:06 +0000979 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000980 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
981
982 -d dir
983 -l list
984 -p password
985 '''
986
987 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000988 print(test.__doc__)
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000989 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +0000990
Tim Peters88869f92001-01-14 23:36:06 +0000991 debugging = 0
992 rcfile = None
993 while sys.argv[1] == '-d':
994 debugging = debugging+1
995 del sys.argv[1]
996 if sys.argv[1][:2] == '-r':
997 # get name of alternate ~/.netrc file:
998 rcfile = sys.argv[1][2:]
999 del sys.argv[1]
1000 host = sys.argv[1]
1001 ftp = FTP(host)
1002 ftp.set_debuglevel(debugging)
1003 userid = passwd = acct = ''
1004 try:
1005 netrc = Netrc(rcfile)
1006 except IOError:
1007 if rcfile is not None:
1008 sys.stderr.write("Could not open account file"
1009 " -- using anonymous login.")
1010 else:
1011 try:
1012 userid, passwd, acct = netrc.get_account(host)
1013 except KeyError:
1014 # no account for host
1015 sys.stderr.write(
1016 "No account -- using anonymous login.")
1017 ftp.login(userid, passwd, acct)
1018 for file in sys.argv[2:]:
1019 if file[:2] == '-l':
1020 ftp.dir(file[2:])
1021 elif file[:2] == '-d':
1022 cmd = 'CWD'
1023 if file[2:]: cmd = cmd + ' ' + file[2:]
1024 resp = ftp.sendcmd(cmd)
1025 elif file == '-p':
1026 ftp.set_pasv(not ftp.passiveserver)
1027 else:
1028 ftp.retrbinary('RETR ' + file, \
1029 sys.stdout.write, 1024)
1030 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +00001031
1032
1033if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +00001034 test()