blob: ada7475998e28d157313f6b5e89441526a37e865 [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
Giampaolo Rodolàbd576b72010-05-10 14:53:29 +0000123 def __enter__(self):
124 return self
125
126 # Context management protocol: try to quit() if active
127 def __exit__(self, *args):
128 if self.sock is not None:
129 try:
130 self.quit()
131 except (socket.error, EOFError):
132 pass
133 finally:
134 if self.sock is not None:
135 self.close()
136
Georg Brandlf78e02b2008-06-10 17:40:04 +0000137 def connect(self, host='', port=0, timeout=-999):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000138 '''Connect to host. Arguments are:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000139 - host: hostname to connect to (string, default previous host)
140 - port: port to connect to (integer, default previous port)
141 '''
142 if host != '':
143 self.host = host
144 if port > 0:
145 self.port = port
Georg Brandlf78e02b2008-06-10 17:40:04 +0000146 if timeout != -999:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000147 self.timeout = timeout
148 self.sock = socket.create_connection((self.host, self.port), self.timeout)
149 self.af = self.sock.family
Guido van Rossum52b89762007-07-17 20:45:57 +0000150 self.file = self.sock.makefile('r', encoding=self.encoding)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000151 self.welcome = self.getresp()
152 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000153
Tim Peters88869f92001-01-14 23:36:06 +0000154 def getwelcome(self):
155 '''Get the welcome message from the server.
156 (this is read and squirreled away by connect())'''
157 if self.debugging:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000158 print('*welcome*', self.sanitize(self.welcome))
Tim Peters88869f92001-01-14 23:36:06 +0000159 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000160
Tim Peters88869f92001-01-14 23:36:06 +0000161 def set_debuglevel(self, level):
162 '''Set the debugging level.
163 The required argument level means:
164 0: no debugging output (default)
165 1: print commands and responses but not body text etc.
166 2: also print raw lines read and sent before stripping CR/LF'''
167 self.debugging = level
168 debug = set_debuglevel
Guido van Rossum1115ab21992-11-04 15:51:30 +0000169
Tim Peters88869f92001-01-14 23:36:06 +0000170 def set_pasv(self, val):
171 '''Use passive or active mode for data transfers.
172 With a false argument, use the normal PORT mode,
173 With a true argument, use the PASV command.'''
174 self.passiveserver = val
Guido van Rossumd2560b01996-05-28 23:41:25 +0000175
Tim Peters88869f92001-01-14 23:36:06 +0000176 # Internal: "sanitize" a string for printing
177 def sanitize(self, s):
178 if s[:5] == 'pass ' or s[:5] == 'PASS ':
179 i = len(s)
180 while i > 5 and s[i-1] in '\r\n':
181 i = i-1
182 s = s[:5] + '*'*(i-5) + s[i:]
Walter Dörwald70a6b492004-02-12 17:35:32 +0000183 return repr(s)
Guido van Rossumebaf1041995-05-05 15:54:14 +0000184
Tim Peters88869f92001-01-14 23:36:06 +0000185 # Internal: send one line to the server, appending CRLF
186 def putline(self, line):
187 line = line + CRLF
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000188 if self.debugging > 1: print('*put*', self.sanitize(line))
Guido van Rossum52b89762007-07-17 20:45:57 +0000189 self.sock.sendall(line.encode(self.encoding))
Guido van Rossum1115ab21992-11-04 15:51:30 +0000190
Tim Peters88869f92001-01-14 23:36:06 +0000191 # Internal: send one command to the server (through putline())
192 def putcmd(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000193 if self.debugging: print('*cmd*', self.sanitize(line))
Tim Peters88869f92001-01-14 23:36:06 +0000194 self.putline(line)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000195
Tim Peters88869f92001-01-14 23:36:06 +0000196 # Internal: return one line from the server, stripping CRLF.
197 # Raise EOFError if the connection is closed
198 def getline(self):
199 line = self.file.readline()
200 if self.debugging > 1:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000201 print('*get*', self.sanitize(line))
Tim Peters88869f92001-01-14 23:36:06 +0000202 if not line: raise EOFError
203 if line[-2:] == CRLF: line = line[:-2]
204 elif line[-1:] in CRLF: line = line[:-1]
205 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000206
Tim Peters88869f92001-01-14 23:36:06 +0000207 # Internal: get a response from the server, which may possibly
208 # consist of multiple lines. Return a single string with no
209 # trailing CRLF. If the response consists of multiple lines,
210 # these are separated by '\n' characters in the string
211 def getmultiline(self):
212 line = self.getline()
213 if line[3:4] == '-':
214 code = line[:3]
215 while 1:
216 nextline = self.getline()
217 line = line + ('\n' + nextline)
218 if nextline[:3] == code and \
219 nextline[3:4] != '-':
220 break
221 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000222
Tim Peters88869f92001-01-14 23:36:06 +0000223 # Internal: get a response from the server.
224 # Raise various errors if the response indicates an error
225 def getresp(self):
226 resp = self.getmultiline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000227 if self.debugging: print('*resp*', self.sanitize(resp))
Tim Peters88869f92001-01-14 23:36:06 +0000228 self.lastresp = resp[:3]
229 c = resp[:1]
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000230 if c in ('1', '2', '3'):
231 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000232 if c == '4':
Collin Winterce36ad82007-08-30 01:19:48 +0000233 raise error_temp(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000234 if c == '5':
Collin Winterce36ad82007-08-30 01:19:48 +0000235 raise error_perm(resp)
236 raise error_proto(resp)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000237
Tim Peters88869f92001-01-14 23:36:06 +0000238 def voidresp(self):
239 """Expect a response beginning with '2'."""
240 resp = self.getresp()
Benjamin Petersond23f8222009-04-05 19:13:16 +0000241 if resp[:1] != '2':
Collin Winterce36ad82007-08-30 01:19:48 +0000242 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000243 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000244
Tim Peters88869f92001-01-14 23:36:06 +0000245 def abort(self):
246 '''Abort a file transfer. Uses out-of-band data.
247 This does not follow the procedure from the RFC to send Telnet
248 IP and Synch; that doesn't seem to work with the servers I've
249 tried. Instead, just send the ABOR command as OOB data.'''
250 line = 'ABOR' + CRLF
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000251 if self.debugging > 1: print('*put urgent*', self.sanitize(line))
Martin v. Löwise12454f2002-02-16 23:06:19 +0000252 self.sock.sendall(line, MSG_OOB)
Tim Peters88869f92001-01-14 23:36:06 +0000253 resp = self.getmultiline()
Giampaolo Rodolàceb513a2010-04-18 13:36:35 +0000254 if resp[:3] not in ('426', '225', '226'):
Collin Winterce36ad82007-08-30 01:19:48 +0000255 raise error_proto(resp)
Guido van Rossumd3166071993-05-24 14:16:22 +0000256
Tim Peters88869f92001-01-14 23:36:06 +0000257 def sendcmd(self, cmd):
258 '''Send a command and return the response.'''
259 self.putcmd(cmd)
260 return self.getresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000261
Tim Peters88869f92001-01-14 23:36:06 +0000262 def voidcmd(self, cmd):
263 """Send a command and expect a response beginning with '2'."""
264 self.putcmd(cmd)
265 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000266
Tim Peters88869f92001-01-14 23:36:06 +0000267 def sendport(self, host, port):
268 '''Send a PORT command with the current host and the given
269 port number.
270 '''
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000271 hbytes = host.split('.')
Benjamin Peterson3a53fbb2008-09-27 22:04:16 +0000272 pbytes = [repr(port//256), repr(port%256)]
Tim Peters88869f92001-01-14 23:36:06 +0000273 bytes = hbytes + pbytes
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000274 cmd = 'PORT ' + ','.join(bytes)
Tim Peters88869f92001-01-14 23:36:06 +0000275 return self.voidcmd(cmd)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000276
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000277 def sendeprt(self, host, port):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000278 '''Send a EPRT command with the current host and the given port number.'''
279 af = 0
280 if self.af == socket.AF_INET:
281 af = 1
282 if self.af == socket.AF_INET6:
283 af = 2
284 if af == 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000285 raise error_proto('unsupported address family')
Walter Dörwald70a6b492004-02-12 17:35:32 +0000286 fields = ['', repr(af), host, repr(port), '']
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000287 cmd = 'EPRT ' + '|'.join(fields)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000288 return self.voidcmd(cmd)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000289
Tim Peters88869f92001-01-14 23:36:06 +0000290 def makeport(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000291 '''Create a new socket and send a PORT command for it.'''
Martin v. Löwis2ad25692001-07-31 08:40:21 +0000292 msg = "getaddrinfo returns an empty list"
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000293 sock = None
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000294 for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
295 af, socktype, proto, canonname, sa = res
296 try:
297 sock = socket.socket(af, socktype, proto)
298 sock.bind(sa)
Guido van Rossumb940e112007-01-10 16:19:56 +0000299 except socket.error as msg:
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000300 if sock:
301 sock.close()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000302 sock = None
303 continue
304 break
305 if not sock:
Collin Winterce36ad82007-08-30 01:19:48 +0000306 raise socket.error(msg)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000307 sock.listen(1)
308 port = sock.getsockname()[1] # Get proper port
309 host = self.sock.getsockname()[0] # Get proper host
310 if self.af == socket.AF_INET:
311 resp = self.sendport(host, port)
312 else:
313 resp = self.sendeprt(host, port)
Giampaolo Rodolà5fb313b2010-04-19 22:05:54 +0000314 if self.timeout is not _GLOBAL_DEFAULT_TIMEOUT:
315 sock.settimeout(self.timeout)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000316 return sock
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000317
318 def makepasv(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000319 if self.af == socket.AF_INET:
320 host, port = parse227(self.sendcmd('PASV'))
321 else:
322 host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
323 return host, port
Guido van Rossum1115ab21992-11-04 15:51:30 +0000324
Tim Peters88869f92001-01-14 23:36:06 +0000325 def ntransfercmd(self, cmd, rest=None):
326 """Initiate a transfer over the data connection.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000327
Tim Peters88869f92001-01-14 23:36:06 +0000328 If the transfer is active, send a port command and the
329 transfer command, and accept the connection. If the server is
330 passive, send a pasv command, connect to it, and start the
331 transfer command. Either way, return the socket for the
332 connection and the expected size of the transfer. The
333 expected size may be None if it could not be determined.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000334
Tim Peters88869f92001-01-14 23:36:06 +0000335 Optional `rest' argument can be a string that is sent as the
Christian Heimes1af737c2008-01-23 08:24:23 +0000336 argument to a REST command. This is essentially a server
Tim Peters88869f92001-01-14 23:36:06 +0000337 marker used to tell the server to skip over any data up to the
338 given marker.
339 """
340 size = None
341 if self.passiveserver:
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000342 host, port = self.makepasv()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000343 conn = socket.create_connection((host, port), self.timeout)
Tim Peters88869f92001-01-14 23:36:06 +0000344 if rest is not None:
345 self.sendcmd("REST %s" % rest)
346 resp = self.sendcmd(cmd)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000347 # Some servers apparently send a 200 reply to
348 # a LIST or STOR command, before the 150 reply
349 # (and way before the 226 reply). This seems to
350 # be in violation of the protocol (which only allows
351 # 1xx or error messages for LIST), so we just discard
352 # this response.
353 if resp[0] == '2':
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000354 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000355 if resp[0] != '1':
Collin Winterce36ad82007-08-30 01:19:48 +0000356 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000357 else:
358 sock = self.makeport()
359 if rest is not None:
360 self.sendcmd("REST %s" % rest)
361 resp = self.sendcmd(cmd)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000362 # See above.
363 if resp[0] == '2':
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000364 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000365 if resp[0] != '1':
Collin Winterce36ad82007-08-30 01:19:48 +0000366 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000367 conn, sockaddr = sock.accept()
Giampaolo Rodolà5fb313b2010-04-19 22:05:54 +0000368 if self.timeout is not _GLOBAL_DEFAULT_TIMEOUT:
369 conn.settimeout(self.timeout)
Tim Peters88869f92001-01-14 23:36:06 +0000370 if resp[:3] == '150':
371 # this is conditional in case we received a 125
372 size = parse150(resp)
373 return conn, size
Fred Drake4de02d91997-01-10 18:26:09 +0000374
Tim Peters88869f92001-01-14 23:36:06 +0000375 def transfercmd(self, cmd, rest=None):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000376 """Like ntransfercmd() but returns only the socket."""
Tim Peters88869f92001-01-14 23:36:06 +0000377 return self.ntransfercmd(cmd, rest)[0]
Guido van Rossumc567c601992-11-05 22:22:37 +0000378
Tim Peters88869f92001-01-14 23:36:06 +0000379 def login(self, user = '', passwd = '', acct = ''):
380 '''Login, default anonymous.'''
381 if not user: user = 'anonymous'
382 if not passwd: passwd = ''
383 if not acct: acct = ''
384 if user == 'anonymous' and passwd in ('', '-'):
Tim Peterse4418602002-02-16 07:34:19 +0000385 # If there is no anonymous ftp password specified
386 # then we'll just use anonymous@
387 # We don't send any other thing because:
388 # - We want to remain anonymous
389 # - We want to stop SPAM
390 # - We don't want to let ftp sites to discriminate by the user,
391 # host or country.
Guido van Rossumc33e0772001-12-28 20:54:28 +0000392 passwd = passwd + 'anonymous@'
Tim Peters88869f92001-01-14 23:36:06 +0000393 resp = self.sendcmd('USER ' + user)
394 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
395 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
396 if resp[0] != '2':
Collin Winterce36ad82007-08-30 01:19:48 +0000397 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000398 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000399
Tim Peters88869f92001-01-14 23:36:06 +0000400 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000401 """Retrieve data in binary mode. A new port is created for you.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000402
Christian Heimes1af737c2008-01-23 08:24:23 +0000403 Args:
404 cmd: A RETR command.
405 callback: A single parameter callable to be called on each
406 block of data read.
407 blocksize: The maximum number of bytes to read from the
408 socket at one time. [default: 8192]
409 rest: Passed to transfercmd(). [default: None]
Guido van Rossum1115ab21992-11-04 15:51:30 +0000410
Christian Heimes1af737c2008-01-23 08:24:23 +0000411 Returns:
412 The response code.
Tim Peters88869f92001-01-14 23:36:06 +0000413 """
414 self.voidcmd('TYPE I')
415 conn = self.transfercmd(cmd, rest)
416 while 1:
417 data = conn.recv(blocksize)
418 if not data:
419 break
420 callback(data)
421 conn.close()
422 return self.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000423
Tim Peters88869f92001-01-14 23:36:06 +0000424 def retrlines(self, cmd, callback = None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000425 """Retrieve data in line mode. A new port is created for you.
426
427 Args:
428 cmd: A RETR, LIST, NLST, or MLSD command.
429 callback: An optional single parameter callable that is called
430 for each line with the trailing CRLF stripped.
431 [default: print_line()]
432
433 Returns:
434 The response code.
435 """
Raymond Hettingere874fc32002-05-12 05:53:51 +0000436 if callback is None: callback = print_line
Tim Peters88869f92001-01-14 23:36:06 +0000437 resp = self.sendcmd('TYPE A')
438 conn = self.transfercmd(cmd)
Guido van Rossum52b89762007-07-17 20:45:57 +0000439 fp = conn.makefile('r', encoding=self.encoding)
Tim Peters88869f92001-01-14 23:36:06 +0000440 while 1:
441 line = fp.readline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000442 if self.debugging > 2: print('*retr*', repr(line))
Tim Peters88869f92001-01-14 23:36:06 +0000443 if not line:
444 break
445 if line[-2:] == CRLF:
446 line = line[:-2]
447 elif line[-1:] == '\n':
448 line = line[:-1]
449 callback(line)
450 fp.close()
451 conn.close()
452 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000453
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000454 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000455 """Store a file in binary mode. A new port is created for you.
456
457 Args:
458 cmd: A STOR command.
459 fp: A file-like object with a read(num_bytes) method.
460 blocksize: The maximum data size to read from fp and send over
461 the connection at once. [default: 8192]
462 callback: An optional single parameter callable that is called on
463 on each block of data after it is sent. [default: None]
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000464 rest: Passed to transfercmd(). [default: None]
Christian Heimes1af737c2008-01-23 08:24:23 +0000465
466 Returns:
467 The response code.
468 """
Tim Peters88869f92001-01-14 23:36:06 +0000469 self.voidcmd('TYPE I')
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000470 conn = self.transfercmd(cmd, rest)
Tim Peters88869f92001-01-14 23:36:06 +0000471 while 1:
472 buf = fp.read(blocksize)
473 if not buf: break
Martin v. Löwise12454f2002-02-16 23:06:19 +0000474 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000475 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000476 conn.close()
477 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000478
Christian Heimes1af737c2008-01-23 08:24:23 +0000479 def storlines(self, cmd, fp, callback=None):
480 """Store a file in line mode. A new port is created for you.
481
482 Args:
483 cmd: A STOR command.
484 fp: A file-like object with a readline() method.
485 callback: An optional single parameter callable that is called on
486 on each line after it is sent. [default: None]
487
488 Returns:
489 The response code.
490 """
Tim Peters88869f92001-01-14 23:36:06 +0000491 self.voidcmd('TYPE A')
492 conn = self.transfercmd(cmd)
493 while 1:
494 buf = fp.readline()
495 if not buf: break
Giampaolo Rodolàb9392352010-08-04 10:12:00 +0000496 if isinstance(buf, str):
497 if not buf.endswith(CRLF):
498 if buf[-1] in CRLF: buf = buf[:-1]
499 buf = buf + CRLF
500 buf = bytes(buf, self.encoding)
501 else:
502 if not buf.endswith(B_CRLF):
503 if buf[-1:] in B_CRLF: buf = buf[:-1]
504 buf = buf + B_CRLF
Martin v. Löwise12454f2002-02-16 23:06:19 +0000505 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000506 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000507 conn.close()
508 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000509
Tim Peters88869f92001-01-14 23:36:06 +0000510 def acct(self, password):
511 '''Send new account name.'''
512 cmd = 'ACCT ' + password
513 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000514
Tim Peters88869f92001-01-14 23:36:06 +0000515 def nlst(self, *args):
516 '''Return a list of files in a given directory (default the current).'''
517 cmd = 'NLST'
518 for arg in args:
519 cmd = cmd + (' ' + arg)
520 files = []
521 self.retrlines(cmd, files.append)
522 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000523
Tim Peters88869f92001-01-14 23:36:06 +0000524 def dir(self, *args):
525 '''List a directory in long form.
526 By default list current directory to stdout.
527 Optional last argument is callback function; all
528 non-empty arguments before it are concatenated to the
529 LIST command. (This *should* only be used for a pathname.)'''
530 cmd = 'LIST'
531 func = None
532 if args[-1:] and type(args[-1]) != type(''):
533 args, func = args[:-1], args[-1]
534 for arg in args:
535 if arg:
536 cmd = cmd + (' ' + arg)
537 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000538
Tim Peters88869f92001-01-14 23:36:06 +0000539 def rename(self, fromname, toname):
540 '''Rename a file.'''
541 resp = self.sendcmd('RNFR ' + fromname)
542 if resp[0] != '3':
Collin Winterce36ad82007-08-30 01:19:48 +0000543 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000544 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000545
Tim Peters88869f92001-01-14 23:36:06 +0000546 def delete(self, filename):
547 '''Delete a file.'''
548 resp = self.sendcmd('DELE ' + filename)
549 if resp[:3] in ('250', '200'):
550 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000551 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000552 raise error_reply(resp)
Guido van Rossum02cf5821993-05-17 08:00:02 +0000553
Tim Peters88869f92001-01-14 23:36:06 +0000554 def cwd(self, dirname):
555 '''Change to a directory.'''
556 if dirname == '..':
557 try:
558 return self.voidcmd('CDUP')
Guido van Rossumb940e112007-01-10 16:19:56 +0000559 except error_perm as msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000560 if msg.args[0][:3] != '500':
561 raise
Tim Peters88869f92001-01-14 23:36:06 +0000562 elif dirname == '':
563 dirname = '.' # does nothing, but could return error
564 cmd = 'CWD ' + dirname
565 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000566
Tim Peters88869f92001-01-14 23:36:06 +0000567 def size(self, filename):
568 '''Retrieve the size of a file.'''
Christian Heimes1af737c2008-01-23 08:24:23 +0000569 # The SIZE command is defined in RFC-3659
Tim Peters88869f92001-01-14 23:36:06 +0000570 resp = self.sendcmd('SIZE ' + filename)
571 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000572 s = resp[3:].strip()
573 try:
574 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000575 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000576 return int(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000577
Tim Peters88869f92001-01-14 23:36:06 +0000578 def mkd(self, dirname):
579 '''Make a directory, return its full pathname.'''
580 resp = self.sendcmd('MKD ' + dirname)
581 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000582
Tim Peters88869f92001-01-14 23:36:06 +0000583 def rmd(self, dirname):
584 '''Remove a directory.'''
585 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000586
Tim Peters88869f92001-01-14 23:36:06 +0000587 def pwd(self):
588 '''Return current working directory.'''
589 resp = self.sendcmd('PWD')
590 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000591
Tim Peters88869f92001-01-14 23:36:06 +0000592 def quit(self):
593 '''Quit, and close the connection.'''
594 resp = self.voidcmd('QUIT')
595 self.close()
596 return resp
597
598 def close(self):
599 '''Close the connection without assuming anything about it.'''
Fred Drake9c98a422001-02-28 21:46:37 +0000600 if self.file:
601 self.file.close()
602 self.sock.close()
603 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000604
605
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000606try:
607 import ssl
608except ImportError:
609 pass
610else:
611 class FTP_TLS(FTP):
612 '''A FTP subclass which adds TLS support to FTP as described
613 in RFC-4217.
614
615 Connect as usual to port 21 implicitly securing the FTP control
616 connection before authenticating.
617
618 Securing the data connection requires user to explicitly ask
619 for it by calling prot_p() method.
620
621 Usage example:
622 >>> from ftplib import FTP_TLS
623 >>> ftps = FTP_TLS('ftp.python.org')
624 >>> ftps.login() # login anonimously previously securing control channel
625 '230 Guest login ok, access restrictions apply.'
626 >>> ftps.prot_p() # switch to secure data connection
627 '200 Protection level set to P'
628 >>> ftps.retrlines('LIST') # list directory content securely
629 total 9
630 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
631 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
632 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
633 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
634 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
635 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
636 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
637 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
638 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
639 '226 Transfer complete.'
640 >>> ftps.quit()
641 '221 Goodbye.'
642 >>>
643 '''
644 ssl_version = ssl.PROTOCOL_TLSv1
645
646 def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000647 certfile=None, context=None,
648 timeout=_GLOBAL_DEFAULT_TIMEOUT):
649 if context is not None and keyfile is not None:
650 raise ValueError("context and keyfile arguments are mutually "
651 "exclusive")
652 if context is not None and certfile is not None:
653 raise ValueError("context and certfile arguments are mutually "
654 "exclusive")
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000655 self.keyfile = keyfile
656 self.certfile = certfile
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000657 self.context = context
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000658 self._prot_p = False
659 FTP.__init__(self, host, user, passwd, acct, timeout)
660
661 def login(self, user='', passwd='', acct='', secure=True):
662 if secure and not isinstance(self.sock, ssl.SSLSocket):
663 self.auth()
664 return FTP.login(self, user, passwd, acct)
665
666 def auth(self):
667 '''Set up secure control connection by using TLS/SSL.'''
668 if isinstance(self.sock, ssl.SSLSocket):
669 raise ValueError("Already using TLS")
670 if self.ssl_version == ssl.PROTOCOL_TLSv1:
671 resp = self.voidcmd('AUTH TLS')
672 else:
673 resp = self.voidcmd('AUTH SSL')
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000674 if self.context is not None:
675 self.sock = self.context.wrap_socket(self.sock)
676 else:
677 self.sock = ssl.wrap_socket(self.sock, self.keyfile,
678 self.certfile,
679 ssl_version=self.ssl_version)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000680 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
681 return resp
682
683 def prot_p(self):
684 '''Set up secure data connection.'''
685 # PROT defines whether or not the data channel is to be protected.
686 # Though RFC-2228 defines four possible protection levels,
687 # RFC-4217 only recommends two, Clear and Private.
688 # Clear (PROT C) means that no security is to be used on the
689 # data-channel, Private (PROT P) means that the data-channel
690 # should be protected by TLS.
691 # PBSZ command MUST still be issued, but must have a parameter of
692 # '0' to indicate that no buffering is taking place and the data
693 # connection should not be encapsulated.
694 self.voidcmd('PBSZ 0')
695 resp = self.voidcmd('PROT P')
696 self._prot_p = True
697 return resp
698
699 def prot_c(self):
700 '''Set up clear text data connection.'''
701 resp = self.voidcmd('PROT C')
702 self._prot_p = False
703 return resp
704
705 # --- Overridden FTP methods
706
707 def ntransfercmd(self, cmd, rest=None):
708 conn, size = FTP.ntransfercmd(self, cmd, rest)
709 if self._prot_p:
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000710 if self.context is not None:
711 conn = self.context.wrap_socket(conn)
712 else:
713 conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
714 ssl_version=self.ssl_version)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000715 return conn, size
716
717 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
718 self.voidcmd('TYPE I')
719 conn = self.transfercmd(cmd, rest)
720 try:
721 while 1:
722 data = conn.recv(blocksize)
723 if not data:
724 break
725 callback(data)
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 retrlines(self, cmd, callback = None):
734 if callback is None: callback = print_line
735 resp = self.sendcmd('TYPE A')
736 conn = self.transfercmd(cmd)
737 fp = conn.makefile('r', encoding=self.encoding)
738 try:
739 while 1:
740 line = fp.readline()
741 if self.debugging > 2: print('*retr*', repr(line))
742 if not line:
743 break
744 if line[-2:] == CRLF:
745 line = line[:-2]
746 elif line[-1:] == '\n':
747 line = line[:-1]
748 callback(line)
749 # shutdown ssl layer
750 if isinstance(conn, ssl.SSLSocket):
751 conn.unwrap()
752 finally:
753 fp.close()
754 conn.close()
755 return self.voidresp()
756
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000757 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000758 self.voidcmd('TYPE I')
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000759 conn = self.transfercmd(cmd, rest)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000760 try:
761 while 1:
762 buf = fp.read(blocksize)
763 if not buf: break
764 conn.sendall(buf)
765 if callback: callback(buf)
766 # shutdown ssl layer
767 if isinstance(conn, ssl.SSLSocket):
768 conn.unwrap()
769 finally:
770 conn.close()
771 return self.voidresp()
772
773 def storlines(self, cmd, fp, callback=None):
774 self.voidcmd('TYPE A')
775 conn = self.transfercmd(cmd)
776 try:
777 while 1:
778 buf = fp.readline()
779 if not buf: break
Giampaolo Rodolàb9392352010-08-04 10:12:00 +0000780 if isinstance(buf, str):
781 if not buf.endswith(CRLF):
782 if buf[-1] in CRLF: buf = buf[:-1]
783 buf = buf + CRLF
784 buf = bytes(buf, self.encoding)
785 else:
786 if not buf.endswith(B_CRLF):
787 if buf[-1:] in B_CRLF: buf = buf[:-1]
788 buf = buf + B_CRLF
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000789 conn.sendall(buf)
790 if callback: callback(buf)
791 # shutdown ssl layer
792 if isinstance(conn, ssl.SSLSocket):
793 conn.unwrap()
794 finally:
795 conn.close()
796 return self.voidresp()
797
Giampaolo Rodolàb9392352010-08-04 10:12:00 +0000798
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000799 __all__.append('FTP_TLS')
800 all_errors = (Error, IOError, EOFError, ssl.SSLError)
801
802
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000803_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000804
805def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000806 '''Parse the '150' response for a RETR request.
807 Returns the expected transfer size or None; size is not guaranteed to
808 be present in the 150 message.
809 '''
810 if resp[:3] != '150':
Collin Winterce36ad82007-08-30 01:19:48 +0000811 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000812 global _150_re
813 if _150_re is None:
814 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000815 _150_re = re.compile(
816 "150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII)
Tim Peters88869f92001-01-14 23:36:06 +0000817 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000818 if not m:
819 return None
820 s = m.group(1)
821 try:
822 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000823 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000824 return int(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000825
826
Guido van Rossum70297d32001-08-17 17:24:29 +0000827_227_re = None
828
Guido van Rossumd2560b01996-05-28 23:41:25 +0000829def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000830 '''Parse the '227' response for a PASV request.
831 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
832 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000833
Tim Peters88869f92001-01-14 23:36:06 +0000834 if resp[:3] != '227':
Collin Winterce36ad82007-08-30 01:19:48 +0000835 raise error_reply(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000836 global _227_re
837 if _227_re is None:
838 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000839 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII)
Guido van Rossum70297d32001-08-17 17:24:29 +0000840 m = _227_re.search(resp)
841 if not m:
Collin Winterce36ad82007-08-30 01:19:48 +0000842 raise error_proto(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000843 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000844 host = '.'.join(numbers[:4])
845 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000846 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000847
848
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000849def parse229(resp, peer):
850 '''Parse the '229' response for a EPSV request.
851 Raises error_proto if it does not contain '(|||port|)'
852 Return ('host.addr.as.numbers', port#) tuple.'''
853
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000854 if resp[:3] != '229':
Collin Winterce36ad82007-08-30 01:19:48 +0000855 raise error_reply(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000856 left = resp.find('(')
Collin Winterce36ad82007-08-30 01:19:48 +0000857 if left < 0: raise error_proto(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000858 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000859 if right < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000860 raise error_proto(resp) # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000861 if resp[left + 1] != resp[right - 1]:
Collin Winterce36ad82007-08-30 01:19:48 +0000862 raise error_proto(resp)
Walter Dörwalda401ae42002-06-03 10:41:45 +0000863 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000864 if len(parts) != 5:
Collin Winterce36ad82007-08-30 01:19:48 +0000865 raise error_proto(resp)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000866 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000867 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000868 return host, port
869
870
Guido van Rossumc567c601992-11-05 22:22:37 +0000871def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000872 '''Parse the '257' response for a MKD or PWD request.
873 This is a response to a MKD or PWD request: a directory name.
874 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000875
Tim Peters88869f92001-01-14 23:36:06 +0000876 if resp[:3] != '257':
Collin Winterce36ad82007-08-30 01:19:48 +0000877 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000878 if resp[3:5] != ' "':
879 return '' # Not compliant to RFC 959, but UNIX ftpd does this
880 dirname = ''
881 i = 5
882 n = len(resp)
883 while i < n:
884 c = resp[i]
885 i = i+1
886 if c == '"':
887 if i >= n or resp[i] != '"':
888 break
889 i = i+1
890 dirname = dirname + c
891 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000892
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000893
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000894def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000895 '''Default retrlines callback to print a line.'''
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000896 print(line)
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000897
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000898
Guido van Rossumd2560b01996-05-28 23:41:25 +0000899def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000900 '''Copy file from one FTP-instance to another.'''
901 if not targetname: targetname = sourcename
902 type = 'TYPE ' + type
903 source.voidcmd(type)
904 target.voidcmd(type)
905 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
906 target.sendport(sourcehost, sourceport)
907 # RFC 959: the user must "listen" [...] BEFORE sending the
908 # transfer request.
909 # So: STOR before RETR, because here the target is a "user".
910 treply = target.sendcmd('STOR ' + targetname)
911 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
912 sreply = source.sendcmd('RETR ' + sourcename)
913 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
914 source.voidresp()
915 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000916
Tim Peters88869f92001-01-14 23:36:06 +0000917
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000918class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000919 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000920
Tim Peters88869f92001-01-14 23:36:06 +0000921 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000922
Tim Peters88869f92001-01-14 23:36:06 +0000923 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000924
Tim Peters88869f92001-01-14 23:36:06 +0000925 """
926 __defuser = None
927 __defpasswd = None
928 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000929
Tim Peters88869f92001-01-14 23:36:06 +0000930 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000931 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000932 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000933 filename = os.path.join(os.environ["HOME"],
934 ".netrc")
935 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000936 raise IOError("specify file to load or set $HOME")
Tim Peters88869f92001-01-14 23:36:06 +0000937 self.__hosts = {}
938 self.__macros = {}
939 fp = open(filename, "r")
940 in_macro = 0
941 while 1:
942 line = fp.readline()
943 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000944 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000945 macro_lines.append(line)
946 continue
947 elif in_macro:
948 self.__macros[macro_name] = tuple(macro_lines)
949 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000950 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000951 host = user = passwd = acct = None
952 default = 0
953 i = 0
954 while i < len(words):
955 w1 = words[i]
956 if i+1 < len(words):
957 w2 = words[i + 1]
958 else:
959 w2 = None
960 if w1 == 'default':
961 default = 1
962 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000963 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000964 i = i + 1
965 elif w1 == 'login' and w2:
966 user = w2
967 i = i + 1
968 elif w1 == 'password' and w2:
969 passwd = w2
970 i = i + 1
971 elif w1 == 'account' and w2:
972 acct = w2
973 i = i + 1
974 elif w1 == 'macdef' and w2:
975 macro_name = w2
976 macro_lines = []
977 in_macro = 1
978 break
979 i = i + 1
980 if default:
981 self.__defuser = user or self.__defuser
982 self.__defpasswd = passwd or self.__defpasswd
983 self.__defacct = acct or self.__defacct
984 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000985 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000986 ouser, opasswd, oacct = \
987 self.__hosts[host]
988 user = user or ouser
989 passwd = passwd or opasswd
990 acct = acct or oacct
991 self.__hosts[host] = user, passwd, acct
992 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000993
Tim Peters88869f92001-01-14 23:36:06 +0000994 def get_hosts(self):
995 """Return a list of hosts mentioned in the .netrc file."""
996 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000997
Tim Peters88869f92001-01-14 23:36:06 +0000998 def get_account(self, host):
999 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +00001000
Tim Peters88869f92001-01-14 23:36:06 +00001001 The return value is a triple containing userid,
1002 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +00001003
Tim Peters88869f92001-01-14 23:36:06 +00001004 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +00001005 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +00001006 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +00001007 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +00001008 user, passwd, acct = self.__hosts[host]
1009 user = user or self.__defuser
1010 passwd = passwd or self.__defpasswd
1011 acct = acct or self.__defacct
1012 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +00001013
Tim Peters88869f92001-01-14 23:36:06 +00001014 def get_macros(self):
1015 """Return a list of all defined macro names."""
1016 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +00001017
Tim Peters88869f92001-01-14 23:36:06 +00001018 def get_macro(self, macro):
1019 """Return a sequence of lines which define a named macro."""
1020 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +00001021
Fred Drake475d51d1997-06-24 22:02:54 +00001022
Tim Peters88869f92001-01-14 23:36:06 +00001023
Guido van Rossum1115ab21992-11-04 15:51:30 +00001024def test():
Tim Peters88869f92001-01-14 23:36:06 +00001025 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001026 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
1027
1028 -d dir
1029 -l list
1030 -p password
1031 '''
1032
1033 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001034 print(test.__doc__)
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001035 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +00001036
Tim Peters88869f92001-01-14 23:36:06 +00001037 debugging = 0
1038 rcfile = None
1039 while sys.argv[1] == '-d':
1040 debugging = debugging+1
1041 del sys.argv[1]
1042 if sys.argv[1][:2] == '-r':
1043 # get name of alternate ~/.netrc file:
1044 rcfile = sys.argv[1][2:]
1045 del sys.argv[1]
1046 host = sys.argv[1]
1047 ftp = FTP(host)
1048 ftp.set_debuglevel(debugging)
1049 userid = passwd = acct = ''
1050 try:
1051 netrc = Netrc(rcfile)
1052 except IOError:
1053 if rcfile is not None:
1054 sys.stderr.write("Could not open account file"
1055 " -- using anonymous login.")
1056 else:
1057 try:
1058 userid, passwd, acct = netrc.get_account(host)
1059 except KeyError:
1060 # no account for host
1061 sys.stderr.write(
1062 "No account -- using anonymous login.")
1063 ftp.login(userid, passwd, acct)
1064 for file in sys.argv[2:]:
1065 if file[:2] == '-l':
1066 ftp.dir(file[2:])
1067 elif file[:2] == '-d':
1068 cmd = 'CWD'
1069 if file[2:]: cmd = cmd + ' ' + file[2:]
1070 resp = ftp.sendcmd(cmd)
1071 elif file == '-p':
1072 ftp.set_pasv(not ftp.passiveserver)
1073 else:
1074 ftp.retrbinary('RETR ' + file, \
1075 sys.stdout.write, 1024)
1076 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +00001077
1078
1079if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +00001080 test()