blob: 8d991582048cb93ca48ca07688321de96d5ab54a [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
Giampaolo RodolĂ 6545ed62010-08-21 20:34:37 +000041import socket
R David Murray87632f12013-02-19 18:32:28 -050042import warnings
Georg Brandlf78e02b2008-06-10 17:40:04 +000043from socket import _GLOBAL_DEFAULT_TIMEOUT
Guido van Rossumb6775db1994-08-01 11:34:53 +000044
Skip Montanaroeccd02a2001-01-20 23:34:12 +000045__all__ = ["FTP","Netrc"]
Guido van Rossum1115ab21992-11-04 15:51:30 +000046
Guido van Rossumd3166071993-05-24 14:16:22 +000047# Magic number from <socket.h>
Tim Peters88869f92001-01-14 23:36:06 +000048MSG_OOB = 0x1 # Process data out of band
Guido van Rossumd3166071993-05-24 14:16:22 +000049
50
Guido van Rossumc567c601992-11-05 22:22:37 +000051# The standard FTP server control port
Guido van Rossum1115ab21992-11-04 15:51:30 +000052FTP_PORT = 21
Guido van Rossum1115ab21992-11-04 15:51:30 +000053
54
Guido van Rossum21974791992-11-06 13:34:17 +000055# Exception raised when an error or invalid response is received
Fred Drake227b1202000-08-17 05:06:49 +000056class Error(Exception): pass
Tim Peters88869f92001-01-14 23:36:06 +000057class error_reply(Error): pass # unexpected [123]xx reply
58class error_temp(Error): pass # 4xx errors
59class error_perm(Error): pass # 5xx errors
60class error_proto(Error): pass # response does not begin with [1-5]
Guido van Rossum1115ab21992-11-04 15:51:30 +000061
62
Guido van Rossum21974791992-11-06 13:34:17 +000063# All exceptions (hopefully) that may be raised here and that aren't
64# (always) programming errors on our side
Andrew Svetlovf7a17b42012-12-25 16:47:37 +020065all_errors = (Error, OSError, EOFError)
Guido van Rossum21974791992-11-06 13:34:17 +000066
67
Guido van Rossum1115ab21992-11-04 15:51:30 +000068# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
69CRLF = '\r\n'
Benjamin Petersonbe17a112008-09-27 21:49:47 +000070B_CRLF = b'\r\n'
Guido van Rossum1115ab21992-11-04 15:51:30 +000071
Guido van Rossum1115ab21992-11-04 15:51:30 +000072# The class itself
73class FTP:
74
Tim Peters88869f92001-01-14 23:36:06 +000075 '''An FTP client class.
Guido van Rossumd2560b01996-05-28 23:41:25 +000076
Guido van Rossumd8faa362007-04-27 19:54:29 +000077 To create a connection, call the class using these arguments:
78 host, user, passwd, acct, timeout
79
80 The first four arguments are all strings, and have default value ''.
81 timeout must be numeric and defaults to None if not passed,
82 meaning that no timeout will be set on any ftp socket(s)
83 If a timeout is passed, then this is now the default timeout for all ftp
84 socket operations for this instance.
85
Tim Peters88869f92001-01-14 23:36:06 +000086 Then use self.connect() with optional host and port argument.
Guido van Rossumd2560b01996-05-28 23:41:25 +000087
Tim Peters88869f92001-01-14 23:36:06 +000088 To download a file, use ftp.retrlines('RETR ' + filename),
89 or ftp.retrbinary() with slightly different arguments.
90 To upload a file, use ftp.storlines() or ftp.storbinary(),
91 which have an open file as argument (see their definitions
92 below for details).
93 The download/upload functions first issue appropriate TYPE
94 and PORT or PASV commands.
Guido van Rossum52b89762007-07-17 20:45:57 +000095 '''
Guido van Rossumd2560b01996-05-28 23:41:25 +000096
Fred Drake9c98a422001-02-28 21:46:37 +000097 debugging = 0
98 host = ''
99 port = FTP_PORT
100 sock = None
101 file = None
102 welcome = None
103 passiveserver = 1
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000104 encoding = "latin-1"
Fred Drake9c98a422001-02-28 21:46:37 +0000105
Tim Peters88869f92001-01-14 23:36:06 +0000106 # Initialization method (called by class instantiation).
107 # Initialize host to localhost, port to standard ftp port
108 # Optional arguments are host (for connect()),
109 # and user, passwd, acct (for login())
Georg Brandlf78e02b2008-06-10 17:40:04 +0000110 def __init__(self, host='', user='', passwd='', acct='',
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000111 timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
112 self.source_address = source_address
Guido van Rossumd8faa362007-04-27 19:54:29 +0000113 self.timeout = timeout
Tim Peters88869f92001-01-14 23:36:06 +0000114 if host:
Fred Drake9c98a422001-02-28 21:46:37 +0000115 self.connect(host)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000116 if user:
117 self.login(user, passwd, acct)
Guido van Rossum52fc1f61993-06-17 12:38:10 +0000118
Giampaolo RodolĂ bd576b72010-05-10 14:53:29 +0000119 def __enter__(self):
120 return self
121
122 # Context management protocol: try to quit() if active
123 def __exit__(self, *args):
124 if self.sock is not None:
125 try:
126 self.quit()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200127 except (OSError, EOFError):
Giampaolo RodolĂ bd576b72010-05-10 14:53:29 +0000128 pass
129 finally:
130 if self.sock is not None:
131 self.close()
132
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000133 def connect(self, host='', port=0, timeout=-999, source_address=None):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000134 '''Connect to host. Arguments are:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000135 - host: hostname to connect to (string, default previous host)
136 - port: port to connect to (integer, default previous port)
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000137 - source_address: a 2-tuple (host, port) for the socket to bind
138 to as its source address before connecting.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000139 '''
140 if host != '':
141 self.host = host
142 if port > 0:
143 self.port = port
Georg Brandlf78e02b2008-06-10 17:40:04 +0000144 if timeout != -999:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000145 self.timeout = timeout
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000146 if source_address is not None:
147 self.source_address = source_address
148 self.sock = socket.create_connection((self.host, self.port), self.timeout,
149 source_address=self.source_address)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000150 self.af = self.sock.family
Guido van Rossum52b89762007-07-17 20:45:57 +0000151 self.file = self.sock.makefile('r', encoding=self.encoding)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000152 self.welcome = self.getresp()
153 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000154
Tim Peters88869f92001-01-14 23:36:06 +0000155 def getwelcome(self):
156 '''Get the welcome message from the server.
157 (this is read and squirreled away by connect())'''
158 if self.debugging:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000159 print('*welcome*', self.sanitize(self.welcome))
Tim Peters88869f92001-01-14 23:36:06 +0000160 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000161
Tim Peters88869f92001-01-14 23:36:06 +0000162 def set_debuglevel(self, level):
163 '''Set the debugging level.
164 The required argument level means:
165 0: no debugging output (default)
166 1: print commands and responses but not body text etc.
167 2: also print raw lines read and sent before stripping CR/LF'''
168 self.debugging = level
169 debug = set_debuglevel
Guido van Rossum1115ab21992-11-04 15:51:30 +0000170
Tim Peters88869f92001-01-14 23:36:06 +0000171 def set_pasv(self, val):
172 '''Use passive or active mode for data transfers.
173 With a false argument, use the normal PORT mode,
174 With a true argument, use the PASV command.'''
175 self.passiveserver = val
Guido van Rossumd2560b01996-05-28 23:41:25 +0000176
Tim Peters88869f92001-01-14 23:36:06 +0000177 # Internal: "sanitize" a string for printing
178 def sanitize(self, s):
Florent Xicluna2bb96f52011-10-23 22:11:00 +0200179 if s[:5] in {'pass ', 'PASS '}:
180 i = len(s.rstrip('\r\n'))
Tim Peters88869f92001-01-14 23:36:06 +0000181 s = s[:5] + '*'*(i-5) + s[i:]
Walter Dörwald70a6b492004-02-12 17:35:32 +0000182 return repr(s)
Guido van Rossumebaf1041995-05-05 15:54:14 +0000183
Tim Peters88869f92001-01-14 23:36:06 +0000184 # Internal: send one line to the server, appending CRLF
185 def putline(self, line):
186 line = line + CRLF
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000187 if self.debugging > 1: print('*put*', self.sanitize(line))
Guido van Rossum52b89762007-07-17 20:45:57 +0000188 self.sock.sendall(line.encode(self.encoding))
Guido van Rossum1115ab21992-11-04 15:51:30 +0000189
Tim Peters88869f92001-01-14 23:36:06 +0000190 # Internal: send one command to the server (through putline())
191 def putcmd(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000192 if self.debugging: print('*cmd*', self.sanitize(line))
Tim Peters88869f92001-01-14 23:36:06 +0000193 self.putline(line)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000194
Tim Peters88869f92001-01-14 23:36:06 +0000195 # Internal: return one line from the server, stripping CRLF.
196 # Raise EOFError if the connection is closed
197 def getline(self):
198 line = self.file.readline()
199 if self.debugging > 1:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000200 print('*get*', self.sanitize(line))
Tim Peters88869f92001-01-14 23:36:06 +0000201 if not line: raise EOFError
202 if line[-2:] == CRLF: line = line[:-2]
203 elif line[-1:] in CRLF: line = line[:-1]
204 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000205
Tim Peters88869f92001-01-14 23:36:06 +0000206 # Internal: get a response from the server, which may possibly
207 # consist of multiple lines. Return a single string with no
208 # trailing CRLF. If the response consists of multiple lines,
209 # these are separated by '\n' characters in the string
210 def getmultiline(self):
211 line = self.getline()
212 if line[3:4] == '-':
213 code = line[:3]
214 while 1:
215 nextline = self.getline()
216 line = line + ('\n' + nextline)
217 if nextline[:3] == code and \
218 nextline[3:4] != '-':
219 break
220 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000221
Tim Peters88869f92001-01-14 23:36:06 +0000222 # Internal: get a response from the server.
223 # Raise various errors if the response indicates an error
224 def getresp(self):
225 resp = self.getmultiline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000226 if self.debugging: print('*resp*', self.sanitize(resp))
Tim Peters88869f92001-01-14 23:36:06 +0000227 self.lastresp = resp[:3]
228 c = resp[:1]
Raymond Hettingerd5825cc2010-09-05 23:15:06 +0000229 if c in {'1', '2', '3'}:
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000230 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000231 if c == '4':
Collin Winterce36ad82007-08-30 01:19:48 +0000232 raise error_temp(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000233 if c == '5':
Collin Winterce36ad82007-08-30 01:19:48 +0000234 raise error_perm(resp)
235 raise error_proto(resp)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000236
Tim Peters88869f92001-01-14 23:36:06 +0000237 def voidresp(self):
238 """Expect a response beginning with '2'."""
239 resp = self.getresp()
Benjamin Petersond23f8222009-04-05 19:13:16 +0000240 if resp[:1] != '2':
Collin Winterce36ad82007-08-30 01:19:48 +0000241 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000242 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000243
Tim Peters88869f92001-01-14 23:36:06 +0000244 def abort(self):
245 '''Abort a file transfer. Uses out-of-band data.
246 This does not follow the procedure from the RFC to send Telnet
247 IP and Synch; that doesn't seem to work with the servers I've
248 tried. Instead, just send the ABOR command as OOB data.'''
Giampaolo Rodola'0b5c21f2011-05-07 19:03:47 +0200249 line = b'ABOR' + B_CRLF
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000250 if self.debugging > 1: print('*put urgent*', self.sanitize(line))
Martin v. Löwise12454f2002-02-16 23:06:19 +0000251 self.sock.sendall(line, MSG_OOB)
Tim Peters88869f92001-01-14 23:36:06 +0000252 resp = self.getmultiline()
Raymond Hettingerd5825cc2010-09-05 23:15:06 +0000253 if resp[:3] not in {'426', '225', '226'}:
Collin Winterce36ad82007-08-30 01:19:48 +0000254 raise error_proto(resp)
Giampaolo Rodola'0b5c21f2011-05-07 19:03:47 +0200255 return 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.'''
Giampaolo Rodola'fc327882012-12-17 14:20:27 +0100292 err = None
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)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200299 except OSError as _:
Giampaolo Rodola'57f34872012-12-17 20:46:16 +0100300 err = _
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000301 if sock:
302 sock.close()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000303 sock = None
304 continue
305 break
Giampaolo Rodola'fc327882012-12-17 14:20:27 +0100306 if sock is None:
307 if err is not None:
308 raise err
309 else:
Andrew Svetlov0832af62012-12-18 23:10:48 +0200310 raise OSError("getaddrinfo returns an empty list")
311 raise OSError(msg)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000312 sock.listen(1)
313 port = sock.getsockname()[1] # Get proper port
314 host = self.sock.getsockname()[0] # Get proper host
315 if self.af == socket.AF_INET:
316 resp = self.sendport(host, port)
317 else:
318 resp = self.sendeprt(host, port)
Giampaolo RodolĂ 5fb313b2010-04-19 22:05:54 +0000319 if self.timeout is not _GLOBAL_DEFAULT_TIMEOUT:
320 sock.settimeout(self.timeout)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000321 return sock
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000322
323 def makepasv(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000324 if self.af == socket.AF_INET:
325 host, port = parse227(self.sendcmd('PASV'))
326 else:
327 host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
328 return host, port
Guido van Rossum1115ab21992-11-04 15:51:30 +0000329
Tim Peters88869f92001-01-14 23:36:06 +0000330 def ntransfercmd(self, cmd, rest=None):
331 """Initiate a transfer over the data connection.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000332
Tim Peters88869f92001-01-14 23:36:06 +0000333 If the transfer is active, send a port command and the
334 transfer command, and accept the connection. If the server is
335 passive, send a pasv command, connect to it, and start the
336 transfer command. Either way, return the socket for the
337 connection and the expected size of the transfer. The
338 expected size may be None if it could not be determined.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000339
Tim Peters88869f92001-01-14 23:36:06 +0000340 Optional `rest' argument can be a string that is sent as the
Christian Heimes1af737c2008-01-23 08:24:23 +0000341 argument to a REST command. This is essentially a server
Tim Peters88869f92001-01-14 23:36:06 +0000342 marker used to tell the server to skip over any data up to the
343 given marker.
344 """
345 size = None
346 if self.passiveserver:
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000347 host, port = self.makepasv()
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000348 conn = socket.create_connection((host, port), self.timeout,
349 source_address=self.source_address)
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200350 try:
351 if rest is not None:
352 self.sendcmd("REST %s" % rest)
353 resp = self.sendcmd(cmd)
354 # Some servers apparently send a 200 reply to
355 # a LIST or STOR command, before the 150 reply
356 # (and way before the 226 reply). This seems to
357 # be in violation of the protocol (which only allows
358 # 1xx or error messages for LIST), so we just discard
359 # this response.
360 if resp[0] == '2':
361 resp = self.getresp()
362 if resp[0] != '1':
363 raise error_reply(resp)
364 except:
365 conn.close()
366 raise
Tim Peters88869f92001-01-14 23:36:06 +0000367 else:
Giampaolo Rodola'836e9aa2011-12-10 21:25:04 +0100368 with self.makeport() as sock:
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200369 if rest is not None:
370 self.sendcmd("REST %s" % rest)
371 resp = self.sendcmd(cmd)
372 # See above.
373 if resp[0] == '2':
374 resp = self.getresp()
375 if resp[0] != '1':
376 raise error_reply(resp)
377 conn, sockaddr = sock.accept()
378 if self.timeout is not _GLOBAL_DEFAULT_TIMEOUT:
379 conn.settimeout(self.timeout)
Tim Peters88869f92001-01-14 23:36:06 +0000380 if resp[:3] == '150':
381 # this is conditional in case we received a 125
382 size = parse150(resp)
383 return conn, size
Fred Drake4de02d91997-01-10 18:26:09 +0000384
Tim Peters88869f92001-01-14 23:36:06 +0000385 def transfercmd(self, cmd, rest=None):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000386 """Like ntransfercmd() but returns only the socket."""
Tim Peters88869f92001-01-14 23:36:06 +0000387 return self.ntransfercmd(cmd, rest)[0]
Guido van Rossumc567c601992-11-05 22:22:37 +0000388
Tim Peters88869f92001-01-14 23:36:06 +0000389 def login(self, user = '', passwd = '', acct = ''):
390 '''Login, default anonymous.'''
391 if not user: user = 'anonymous'
392 if not passwd: passwd = ''
393 if not acct: acct = ''
Raymond Hettingerd5825cc2010-09-05 23:15:06 +0000394 if user == 'anonymous' and passwd in {'', '-'}:
Tim Peterse4418602002-02-16 07:34:19 +0000395 # If there is no anonymous ftp password specified
396 # then we'll just use anonymous@
397 # We don't send any other thing because:
398 # - We want to remain anonymous
399 # - We want to stop SPAM
400 # - We don't want to let ftp sites to discriminate by the user,
401 # host or country.
Guido van Rossumc33e0772001-12-28 20:54:28 +0000402 passwd = passwd + 'anonymous@'
Tim Peters88869f92001-01-14 23:36:06 +0000403 resp = self.sendcmd('USER ' + user)
404 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
405 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
406 if resp[0] != '2':
Collin Winterce36ad82007-08-30 01:19:48 +0000407 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000408 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000409
Tim Peters88869f92001-01-14 23:36:06 +0000410 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000411 """Retrieve data in binary mode. A new port is created for you.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000412
Christian Heimes1af737c2008-01-23 08:24:23 +0000413 Args:
414 cmd: A RETR command.
415 callback: A single parameter callable to be called on each
416 block of data read.
417 blocksize: The maximum number of bytes to read from the
418 socket at one time. [default: 8192]
419 rest: Passed to transfercmd(). [default: None]
Guido van Rossum1115ab21992-11-04 15:51:30 +0000420
Christian Heimes1af737c2008-01-23 08:24:23 +0000421 Returns:
422 The response code.
Tim Peters88869f92001-01-14 23:36:06 +0000423 """
424 self.voidcmd('TYPE I')
Benjamin Petersona8071372010-10-31 18:21:16 +0000425 with self.transfercmd(cmd, rest) as conn:
426 while 1:
427 data = conn.recv(blocksize)
428 if not data:
429 break
430 callback(data)
Tim Peters88869f92001-01-14 23:36:06 +0000431 return self.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000432
Tim Peters88869f92001-01-14 23:36:06 +0000433 def retrlines(self, cmd, callback = None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000434 """Retrieve data in line mode. A new port is created for you.
435
436 Args:
Giampaolo Rodola'd78def92011-05-06 19:49:08 +0200437 cmd: A RETR, LIST, or NLST command.
Christian Heimes1af737c2008-01-23 08:24:23 +0000438 callback: An optional single parameter callable that is called
439 for each line with the trailing CRLF stripped.
440 [default: print_line()]
441
442 Returns:
443 The response code.
444 """
Raymond Hettingere874fc32002-05-12 05:53:51 +0000445 if callback is None: callback = print_line
Tim Peters88869f92001-01-14 23:36:06 +0000446 resp = self.sendcmd('TYPE A')
Benjamin Petersona8071372010-10-31 18:21:16 +0000447 with self.transfercmd(cmd) as conn, \
448 conn.makefile('r', encoding=self.encoding) as fp:
449 while 1:
450 line = fp.readline()
451 if self.debugging > 2: print('*retr*', repr(line))
452 if not line:
453 break
454 if line[-2:] == CRLF:
455 line = line[:-2]
456 elif line[-1:] == '\n':
457 line = line[:-1]
458 callback(line)
Tim Peters88869f92001-01-14 23:36:06 +0000459 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000460
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000461 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Christian Heimes1af737c2008-01-23 08:24:23 +0000462 """Store a file in binary mode. A new port is created for you.
463
464 Args:
465 cmd: A STOR command.
466 fp: A file-like object with a read(num_bytes) method.
467 blocksize: The maximum data size to read from fp and send over
468 the connection at once. [default: 8192]
469 callback: An optional single parameter callable that is called on
470 on each block of data after it is sent. [default: None]
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000471 rest: Passed to transfercmd(). [default: None]
Christian Heimes1af737c2008-01-23 08:24:23 +0000472
473 Returns:
474 The response code.
475 """
Tim Peters88869f92001-01-14 23:36:06 +0000476 self.voidcmd('TYPE I')
Benjamin Petersona8071372010-10-31 18:21:16 +0000477 with self.transfercmd(cmd, rest) as conn:
478 while 1:
479 buf = fp.read(blocksize)
480 if not buf: break
481 conn.sendall(buf)
482 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000483 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000484
Christian Heimes1af737c2008-01-23 08:24:23 +0000485 def storlines(self, cmd, fp, callback=None):
486 """Store a file in line mode. A new port is created for you.
487
488 Args:
489 cmd: A STOR command.
490 fp: A file-like object with a readline() method.
491 callback: An optional single parameter callable that is called on
492 on each line after it is sent. [default: None]
493
494 Returns:
495 The response code.
496 """
Tim Peters88869f92001-01-14 23:36:06 +0000497 self.voidcmd('TYPE A')
Benjamin Petersona8071372010-10-31 18:21:16 +0000498 with self.transfercmd(cmd) as conn:
499 while 1:
500 buf = fp.readline()
501 if not buf: break
502 if buf[-2:] != B_CRLF:
503 if buf[-1] in B_CRLF: buf = buf[:-1]
504 buf = buf + B_CRLF
505 conn.sendall(buf)
506 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000507 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000508
Tim Peters88869f92001-01-14 23:36:06 +0000509 def acct(self, password):
510 '''Send new account name.'''
511 cmd = 'ACCT ' + password
512 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000513
Tim Peters88869f92001-01-14 23:36:06 +0000514 def nlst(self, *args):
515 '''Return a list of files in a given directory (default the current).'''
516 cmd = 'NLST'
517 for arg in args:
518 cmd = cmd + (' ' + arg)
519 files = []
520 self.retrlines(cmd, files.append)
521 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000522
Tim Peters88869f92001-01-14 23:36:06 +0000523 def dir(self, *args):
524 '''List a directory in long form.
525 By default list current directory to stdout.
526 Optional last argument is callback function; all
527 non-empty arguments before it are concatenated to the
528 LIST command. (This *should* only be used for a pathname.)'''
529 cmd = 'LIST'
530 func = None
531 if args[-1:] and type(args[-1]) != type(''):
532 args, func = args[:-1], args[-1]
533 for arg in args:
534 if arg:
535 cmd = cmd + (' ' + arg)
536 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000537
Giampaolo Rodola'd78def92011-05-06 19:49:08 +0200538 def mlsd(self, path="", facts=[]):
539 '''List a directory in a standardized format by using MLSD
540 command (RFC-3659). If path is omitted the current directory
541 is assumed. "facts" is a list of strings representing the type
542 of information desired (e.g. ["type", "size", "perm"]).
543
544 Return a generator object yielding a tuple of two elements
545 for every file found in path.
546 First element is the file name, the second one is a dictionary
547 including a variable number of "facts" depending on the server
548 and whether "facts" argument has been provided.
549 '''
550 if facts:
551 self.sendcmd("OPTS MLST " + ";".join(facts) + ";")
552 if path:
553 cmd = "MLSD %s" % path
554 else:
555 cmd = "MLSD"
556 lines = []
557 self.retrlines(cmd, lines.append)
558 for line in lines:
559 facts_found, _, name = line.rstrip(CRLF).partition(' ')
560 entry = {}
561 for fact in facts_found[:-1].split(";"):
562 key, _, value = fact.partition("=")
563 entry[key.lower()] = value
564 yield (name, entry)
565
Tim Peters88869f92001-01-14 23:36:06 +0000566 def rename(self, fromname, toname):
567 '''Rename a file.'''
568 resp = self.sendcmd('RNFR ' + fromname)
569 if resp[0] != '3':
Collin Winterce36ad82007-08-30 01:19:48 +0000570 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000571 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000572
Tim Peters88869f92001-01-14 23:36:06 +0000573 def delete(self, filename):
574 '''Delete a file.'''
575 resp = self.sendcmd('DELE ' + filename)
Raymond Hettingerd5825cc2010-09-05 23:15:06 +0000576 if resp[:3] in {'250', '200'}:
Tim Peters88869f92001-01-14 23:36:06 +0000577 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000578 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000579 raise error_reply(resp)
Guido van Rossum02cf5821993-05-17 08:00:02 +0000580
Tim Peters88869f92001-01-14 23:36:06 +0000581 def cwd(self, dirname):
582 '''Change to a directory.'''
583 if dirname == '..':
584 try:
585 return self.voidcmd('CDUP')
Guido van Rossumb940e112007-01-10 16:19:56 +0000586 except error_perm as msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000587 if msg.args[0][:3] != '500':
588 raise
Tim Peters88869f92001-01-14 23:36:06 +0000589 elif dirname == '':
590 dirname = '.' # does nothing, but could return error
591 cmd = 'CWD ' + dirname
592 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000593
Tim Peters88869f92001-01-14 23:36:06 +0000594 def size(self, filename):
595 '''Retrieve the size of a file.'''
Christian Heimes1af737c2008-01-23 08:24:23 +0000596 # The SIZE command is defined in RFC-3659
Tim Peters88869f92001-01-14 23:36:06 +0000597 resp = self.sendcmd('SIZE ' + filename)
598 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000599 s = resp[3:].strip()
Florent Xicluna2bb96f52011-10-23 22:11:00 +0200600 return int(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000601
Tim Peters88869f92001-01-14 23:36:06 +0000602 def mkd(self, dirname):
603 '''Make a directory, return its full pathname.'''
Giampaolo RodolĂ bbc47822010-08-23 22:10:32 +0000604 resp = self.voidcmd('MKD ' + dirname)
605 # fix around non-compliant implementations such as IIS shipped
606 # with Windows server 2003
607 if not resp.startswith('257'):
608 return ''
Tim Peters88869f92001-01-14 23:36:06 +0000609 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000610
Tim Peters88869f92001-01-14 23:36:06 +0000611 def rmd(self, dirname):
612 '''Remove a directory.'''
613 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000614
Tim Peters88869f92001-01-14 23:36:06 +0000615 def pwd(self):
616 '''Return current working directory.'''
Giampaolo RodolĂ bbc47822010-08-23 22:10:32 +0000617 resp = self.voidcmd('PWD')
618 # fix around non-compliant implementations such as IIS shipped
619 # with Windows server 2003
620 if not resp.startswith('257'):
621 return ''
Tim Peters88869f92001-01-14 23:36:06 +0000622 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000623
Tim Peters88869f92001-01-14 23:36:06 +0000624 def quit(self):
625 '''Quit, and close the connection.'''
626 resp = self.voidcmd('QUIT')
627 self.close()
628 return resp
629
630 def close(self):
631 '''Close the connection without assuming anything about it.'''
Giampaolo RodolĂ d6868482011-02-22 19:24:33 +0000632 if self.file is not None:
Fred Drake9c98a422001-02-28 21:46:37 +0000633 self.file.close()
Giampaolo RodolĂ d6868482011-02-22 19:24:33 +0000634 if self.sock is not None:
Fred Drake9c98a422001-02-28 21:46:37 +0000635 self.sock.close()
Giampaolo RodolĂ d6868482011-02-22 19:24:33 +0000636 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000637
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000638try:
639 import ssl
640except ImportError:
641 pass
642else:
643 class FTP_TLS(FTP):
644 '''A FTP subclass which adds TLS support to FTP as described
645 in RFC-4217.
646
647 Connect as usual to port 21 implicitly securing the FTP control
648 connection before authenticating.
649
650 Securing the data connection requires user to explicitly ask
651 for it by calling prot_p() method.
652
653 Usage example:
654 >>> from ftplib import FTP_TLS
655 >>> ftps = FTP_TLS('ftp.python.org')
Ezio Melotti4969f702011-03-15 05:59:46 +0200656 >>> ftps.login() # login anonymously previously securing control channel
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000657 '230 Guest login ok, access restrictions apply.'
658 >>> ftps.prot_p() # switch to secure data connection
659 '200 Protection level set to P'
660 >>> ftps.retrlines('LIST') # list directory content securely
661 total 9
662 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
663 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
664 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
665 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
666 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
667 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
668 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
669 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
670 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
671 '226 Transfer complete.'
672 >>> ftps.quit()
673 '221 Goodbye.'
674 >>>
675 '''
676 ssl_version = ssl.PROTOCOL_TLSv1
677
678 def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
Giampaolo RodolĂ a67299e2010-05-26 18:06:04 +0000679 certfile=None, context=None,
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000680 timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
Giampaolo RodolĂ a67299e2010-05-26 18:06:04 +0000681 if context is not None and keyfile is not None:
682 raise ValueError("context and keyfile arguments are mutually "
683 "exclusive")
684 if context is not None and certfile is not None:
685 raise ValueError("context and certfile arguments are mutually "
686 "exclusive")
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000687 self.keyfile = keyfile
688 self.certfile = certfile
Giampaolo RodolĂ a67299e2010-05-26 18:06:04 +0000689 self.context = context
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000690 self._prot_p = False
Giampaolo RodolĂ 396ff062011-02-28 19:19:51 +0000691 FTP.__init__(self, host, user, passwd, acct, timeout, source_address)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000692
693 def login(self, user='', passwd='', acct='', secure=True):
694 if secure and not isinstance(self.sock, ssl.SSLSocket):
695 self.auth()
696 return FTP.login(self, user, passwd, acct)
697
698 def auth(self):
699 '''Set up secure control connection by using TLS/SSL.'''
700 if isinstance(self.sock, ssl.SSLSocket):
701 raise ValueError("Already using TLS")
702 if self.ssl_version == ssl.PROTOCOL_TLSv1:
703 resp = self.voidcmd('AUTH TLS')
704 else:
705 resp = self.voidcmd('AUTH SSL')
Giampaolo RodolĂ a67299e2010-05-26 18:06:04 +0000706 if self.context is not None:
707 self.sock = self.context.wrap_socket(self.sock)
708 else:
709 self.sock = ssl.wrap_socket(self.sock, self.keyfile,
710 self.certfile,
711 ssl_version=self.ssl_version)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000712 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
713 return resp
714
Giampaolo Rodola'096dcb12011-06-27 11:17:51 +0200715 def ccc(self):
716 '''Switch back to a clear-text control connection.'''
717 if not isinstance(self.sock, ssl.SSLSocket):
718 raise ValueError("not using TLS")
719 resp = self.voidcmd('CCC')
720 self.sock = self.sock.unwrap()
721 return resp
722
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000723 def prot_p(self):
724 '''Set up secure data connection.'''
725 # PROT defines whether or not the data channel is to be protected.
726 # Though RFC-2228 defines four possible protection levels,
727 # RFC-4217 only recommends two, Clear and Private.
728 # Clear (PROT C) means that no security is to be used on the
729 # data-channel, Private (PROT P) means that the data-channel
730 # should be protected by TLS.
731 # PBSZ command MUST still be issued, but must have a parameter of
732 # '0' to indicate that no buffering is taking place and the data
733 # connection should not be encapsulated.
734 self.voidcmd('PBSZ 0')
735 resp = self.voidcmd('PROT P')
736 self._prot_p = True
737 return resp
738
739 def prot_c(self):
740 '''Set up clear text data connection.'''
741 resp = self.voidcmd('PROT C')
742 self._prot_p = False
743 return resp
744
745 # --- Overridden FTP methods
746
747 def ntransfercmd(self, cmd, rest=None):
748 conn, size = FTP.ntransfercmd(self, cmd, rest)
749 if self._prot_p:
Giampaolo RodolĂ a67299e2010-05-26 18:06:04 +0000750 if self.context is not None:
751 conn = self.context.wrap_socket(conn)
752 else:
753 conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
754 ssl_version=self.ssl_version)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000755 return conn, size
756
757 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
758 self.voidcmd('TYPE I')
Giampaolo Rodola'836e9aa2011-12-10 21:25:04 +0100759 with self.transfercmd(cmd, rest) as conn:
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000760 while 1:
761 data = conn.recv(blocksize)
762 if not data:
763 break
764 callback(data)
765 # shutdown ssl layer
766 if isinstance(conn, ssl.SSLSocket):
767 conn.unwrap()
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000768 return self.voidresp()
769
770 def retrlines(self, cmd, callback = None):
771 if callback is None: callback = print_line
772 resp = self.sendcmd('TYPE A')
773 conn = self.transfercmd(cmd)
774 fp = conn.makefile('r', encoding=self.encoding)
Giampaolo Rodola'836e9aa2011-12-10 21:25:04 +0100775 with fp, conn:
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000776 while 1:
777 line = fp.readline()
778 if self.debugging > 2: print('*retr*', repr(line))
779 if not line:
780 break
781 if line[-2:] == CRLF:
782 line = line[:-2]
783 elif line[-1:] == '\n':
784 line = line[:-1]
785 callback(line)
786 # shutdown ssl layer
787 if isinstance(conn, ssl.SSLSocket):
788 conn.unwrap()
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000789 return self.voidresp()
790
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000791 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000792 self.voidcmd('TYPE I')
Giampaolo Rodola'836e9aa2011-12-10 21:25:04 +0100793 with self.transfercmd(cmd, rest) as conn:
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000794 while 1:
795 buf = fp.read(blocksize)
796 if not buf: break
797 conn.sendall(buf)
798 if callback: callback(buf)
799 # shutdown ssl layer
800 if isinstance(conn, ssl.SSLSocket):
801 conn.unwrap()
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000802 return self.voidresp()
803
804 def storlines(self, cmd, fp, callback=None):
805 self.voidcmd('TYPE A')
Giampaolo Rodola'836e9aa2011-12-10 21:25:04 +0100806 with self.transfercmd(cmd) as conn:
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000807 while 1:
808 buf = fp.readline()
809 if not buf: break
Giampaolo RodolĂ f96482e2010-08-04 10:36:18 +0000810 if buf[-2:] != B_CRLF:
811 if buf[-1] in B_CRLF: buf = buf[:-1]
812 buf = buf + B_CRLF
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000813 conn.sendall(buf)
814 if callback: callback(buf)
815 # shutdown ssl layer
816 if isinstance(conn, ssl.SSLSocket):
817 conn.unwrap()
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000818 return self.voidresp()
819
Giampaolo Rodola'24befa82011-05-07 19:09:34 +0200820 def abort(self):
821 # overridden as we can't pass MSG_OOB flag to sendall()
822 line = b'ABOR' + B_CRLF
823 self.sock.sendall(line)
824 resp = self.getmultiline()
825 if resp[:3] not in {'426', '225', '226'}:
826 raise error_proto(resp)
827 return resp
828
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000829 __all__.append('FTP_TLS')
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200830 all_errors = (Error, OSError, EOFError, ssl.SSLError)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000831
832
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000833_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000834
835def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000836 '''Parse the '150' response for a RETR request.
837 Returns the expected transfer size or None; size is not guaranteed to
838 be present in the 150 message.
839 '''
840 if resp[:3] != '150':
Collin Winterce36ad82007-08-30 01:19:48 +0000841 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000842 global _150_re
843 if _150_re is None:
844 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000845 _150_re = re.compile(
846 "150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII)
Tim Peters88869f92001-01-14 23:36:06 +0000847 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000848 if not m:
849 return None
Florent Xicluna2bb96f52011-10-23 22:11:00 +0200850 return int(m.group(1))
Fred Drake4de02d91997-01-10 18:26:09 +0000851
852
Guido van Rossum70297d32001-08-17 17:24:29 +0000853_227_re = None
854
Guido van Rossumd2560b01996-05-28 23:41:25 +0000855def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000856 '''Parse the '227' response for a PASV request.
857 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
858 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000859
Tim Peters88869f92001-01-14 23:36:06 +0000860 if resp[:3] != '227':
Collin Winterce36ad82007-08-30 01:19:48 +0000861 raise error_reply(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000862 global _227_re
863 if _227_re is None:
864 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000865 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII)
Guido van Rossum70297d32001-08-17 17:24:29 +0000866 m = _227_re.search(resp)
867 if not m:
Collin Winterce36ad82007-08-30 01:19:48 +0000868 raise error_proto(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000869 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000870 host = '.'.join(numbers[:4])
871 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000872 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000873
874
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000875def parse229(resp, peer):
876 '''Parse the '229' response for a EPSV request.
877 Raises error_proto if it does not contain '(|||port|)'
878 Return ('host.addr.as.numbers', port#) tuple.'''
879
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000880 if resp[:3] != '229':
Collin Winterce36ad82007-08-30 01:19:48 +0000881 raise error_reply(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000882 left = resp.find('(')
Collin Winterce36ad82007-08-30 01:19:48 +0000883 if left < 0: raise error_proto(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000884 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000885 if right < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000886 raise error_proto(resp) # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000887 if resp[left + 1] != resp[right - 1]:
Collin Winterce36ad82007-08-30 01:19:48 +0000888 raise error_proto(resp)
Walter Dörwalda401ae42002-06-03 10:41:45 +0000889 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000890 if len(parts) != 5:
Collin Winterce36ad82007-08-30 01:19:48 +0000891 raise error_proto(resp)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000892 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000893 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000894 return host, port
895
896
Guido van Rossumc567c601992-11-05 22:22:37 +0000897def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000898 '''Parse the '257' response for a MKD or PWD request.
899 This is a response to a MKD or PWD request: a directory name.
900 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000901
Tim Peters88869f92001-01-14 23:36:06 +0000902 if resp[:3] != '257':
Collin Winterce36ad82007-08-30 01:19:48 +0000903 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000904 if resp[3:5] != ' "':
905 return '' # Not compliant to RFC 959, but UNIX ftpd does this
906 dirname = ''
907 i = 5
908 n = len(resp)
909 while i < n:
910 c = resp[i]
911 i = i+1
912 if c == '"':
913 if i >= n or resp[i] != '"':
914 break
915 i = i+1
916 dirname = dirname + c
917 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000918
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000919
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000920def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000921 '''Default retrlines callback to print a line.'''
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000922 print(line)
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000923
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000924
Guido van Rossumd2560b01996-05-28 23:41:25 +0000925def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000926 '''Copy file from one FTP-instance to another.'''
927 if not targetname: targetname = sourcename
928 type = 'TYPE ' + type
929 source.voidcmd(type)
930 target.voidcmd(type)
931 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
932 target.sendport(sourcehost, sourceport)
933 # RFC 959: the user must "listen" [...] BEFORE sending the
934 # transfer request.
935 # So: STOR before RETR, because here the target is a "user".
936 treply = target.sendcmd('STOR ' + targetname)
Raymond Hettingerd5825cc2010-09-05 23:15:06 +0000937 if treply[:3] not in {'125', '150'}: raise error_proto # RFC 959
Tim Peters88869f92001-01-14 23:36:06 +0000938 sreply = source.sendcmd('RETR ' + sourcename)
Raymond Hettingerd5825cc2010-09-05 23:15:06 +0000939 if sreply[:3] not in {'125', '150'}: raise error_proto # RFC 959
Tim Peters88869f92001-01-14 23:36:06 +0000940 source.voidresp()
941 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000942
Tim Peters88869f92001-01-14 23:36:06 +0000943
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000944class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000945 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000946
Tim Peters88869f92001-01-14 23:36:06 +0000947 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000948
Tim Peters88869f92001-01-14 23:36:06 +0000949 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000950
Tim Peters88869f92001-01-14 23:36:06 +0000951 """
952 __defuser = None
953 __defpasswd = None
954 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000955
Tim Peters88869f92001-01-14 23:36:06 +0000956 def __init__(self, filename=None):
R David Murray87632f12013-02-19 18:32:28 -0500957 warnings.warn("This class is deprecated, use the netrc module instead",
958 DeprecationWarning, 2)
Raymond Hettinger094662a2002-06-01 01:29:16 +0000959 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000960 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000961 filename = os.path.join(os.environ["HOME"],
962 ".netrc")
963 else:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200964 raise OSError("specify file to load or set $HOME")
Tim Peters88869f92001-01-14 23:36:06 +0000965 self.__hosts = {}
966 self.__macros = {}
967 fp = open(filename, "r")
968 in_macro = 0
969 while 1:
970 line = fp.readline()
971 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000972 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000973 macro_lines.append(line)
974 continue
975 elif in_macro:
976 self.__macros[macro_name] = tuple(macro_lines)
977 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000978 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000979 host = user = passwd = acct = None
980 default = 0
981 i = 0
982 while i < len(words):
983 w1 = words[i]
984 if i+1 < len(words):
985 w2 = words[i + 1]
986 else:
987 w2 = None
988 if w1 == 'default':
989 default = 1
990 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000991 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000992 i = i + 1
993 elif w1 == 'login' and w2:
994 user = w2
995 i = i + 1
996 elif w1 == 'password' and w2:
997 passwd = w2
998 i = i + 1
999 elif w1 == 'account' and w2:
1000 acct = w2
1001 i = i + 1
1002 elif w1 == 'macdef' and w2:
1003 macro_name = w2
1004 macro_lines = []
1005 in_macro = 1
1006 break
1007 i = i + 1
1008 if default:
1009 self.__defuser = user or self.__defuser
1010 self.__defpasswd = passwd or self.__defpasswd
1011 self.__defacct = acct or self.__defacct
1012 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001013 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +00001014 ouser, opasswd, oacct = \
1015 self.__hosts[host]
1016 user = user or ouser
1017 passwd = passwd or opasswd
1018 acct = acct or oacct
1019 self.__hosts[host] = user, passwd, acct
1020 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +00001021
Tim Peters88869f92001-01-14 23:36:06 +00001022 def get_hosts(self):
1023 """Return a list of hosts mentioned in the .netrc file."""
1024 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +00001025
Tim Peters88869f92001-01-14 23:36:06 +00001026 def get_account(self, host):
1027 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +00001028
Tim Peters88869f92001-01-14 23:36:06 +00001029 The return value is a triple containing userid,
1030 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +00001031
Tim Peters88869f92001-01-14 23:36:06 +00001032 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +00001033 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +00001034 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +00001035 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +00001036 user, passwd, acct = self.__hosts[host]
1037 user = user or self.__defuser
1038 passwd = passwd or self.__defpasswd
1039 acct = acct or self.__defacct
1040 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +00001041
Tim Peters88869f92001-01-14 23:36:06 +00001042 def get_macros(self):
1043 """Return a list of all defined macro names."""
1044 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +00001045
Tim Peters88869f92001-01-14 23:36:06 +00001046 def get_macro(self, macro):
1047 """Return a sequence of lines which define a named macro."""
1048 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +00001049
Fred Drake475d51d1997-06-24 22:02:54 +00001050
Tim Peters88869f92001-01-14 23:36:06 +00001051
Guido van Rossum1115ab21992-11-04 15:51:30 +00001052def test():
Tim Peters88869f92001-01-14 23:36:06 +00001053 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001054 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
1055
1056 -d dir
1057 -l list
1058 -p password
1059 '''
1060
1061 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001062 print(test.__doc__)
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001063 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +00001064
Tim Peters88869f92001-01-14 23:36:06 +00001065 debugging = 0
1066 rcfile = None
1067 while sys.argv[1] == '-d':
1068 debugging = debugging+1
1069 del sys.argv[1]
1070 if sys.argv[1][:2] == '-r':
1071 # get name of alternate ~/.netrc file:
1072 rcfile = sys.argv[1][2:]
1073 del sys.argv[1]
1074 host = sys.argv[1]
1075 ftp = FTP(host)
1076 ftp.set_debuglevel(debugging)
1077 userid = passwd = acct = ''
1078 try:
1079 netrc = Netrc(rcfile)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001080 except OSError:
Tim Peters88869f92001-01-14 23:36:06 +00001081 if rcfile is not None:
1082 sys.stderr.write("Could not open account file"
1083 " -- using anonymous login.")
1084 else:
1085 try:
1086 userid, passwd, acct = netrc.get_account(host)
1087 except KeyError:
1088 # no account for host
1089 sys.stderr.write(
1090 "No account -- using anonymous login.")
1091 ftp.login(userid, passwd, acct)
1092 for file in sys.argv[2:]:
1093 if file[:2] == '-l':
1094 ftp.dir(file[2:])
1095 elif file[:2] == '-d':
1096 cmd = 'CWD'
1097 if file[2:]: cmd = cmd + ' ' + file[2:]
1098 resp = ftp.sendcmd(cmd)
1099 elif file == '-p':
1100 ftp.set_pasv(not ftp.passiveserver)
1101 else:
1102 ftp.retrbinary('RETR ' + file, \
1103 sys.stdout.write, 1024)
1104 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +00001105
1106
1107if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +00001108 test()