blob: b593fa1e76c1a7cc82bc6329184d5376433df25d [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
Benjamin Petersonbe17a112008-09-27 21:49:47 +0000496 if buf[-2:] != B_CRLF:
497 if buf[-1] in B_CRLF: buf = buf[:-1]
498 buf = buf + B_CRLF
Martin v. Löwise12454f2002-02-16 23:06:19 +0000499 conn.sendall(buf)
Christian Heimes1af737c2008-01-23 08:24:23 +0000500 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000501 conn.close()
502 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000503
Tim Peters88869f92001-01-14 23:36:06 +0000504 def acct(self, password):
505 '''Send new account name.'''
506 cmd = 'ACCT ' + password
507 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000508
Tim Peters88869f92001-01-14 23:36:06 +0000509 def nlst(self, *args):
510 '''Return a list of files in a given directory (default the current).'''
511 cmd = 'NLST'
512 for arg in args:
513 cmd = cmd + (' ' + arg)
514 files = []
515 self.retrlines(cmd, files.append)
516 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000517
Tim Peters88869f92001-01-14 23:36:06 +0000518 def dir(self, *args):
519 '''List a directory in long form.
520 By default list current directory to stdout.
521 Optional last argument is callback function; all
522 non-empty arguments before it are concatenated to the
523 LIST command. (This *should* only be used for a pathname.)'''
524 cmd = 'LIST'
525 func = None
526 if args[-1:] and type(args[-1]) != type(''):
527 args, func = args[:-1], args[-1]
528 for arg in args:
529 if arg:
530 cmd = cmd + (' ' + arg)
531 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000532
Tim Peters88869f92001-01-14 23:36:06 +0000533 def rename(self, fromname, toname):
534 '''Rename a file.'''
535 resp = self.sendcmd('RNFR ' + fromname)
536 if resp[0] != '3':
Collin Winterce36ad82007-08-30 01:19:48 +0000537 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000538 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000539
Tim Peters88869f92001-01-14 23:36:06 +0000540 def delete(self, filename):
541 '''Delete a file.'''
542 resp = self.sendcmd('DELE ' + filename)
543 if resp[:3] in ('250', '200'):
544 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000545 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000546 raise error_reply(resp)
Guido van Rossum02cf5821993-05-17 08:00:02 +0000547
Tim Peters88869f92001-01-14 23:36:06 +0000548 def cwd(self, dirname):
549 '''Change to a directory.'''
550 if dirname == '..':
551 try:
552 return self.voidcmd('CDUP')
Guido van Rossumb940e112007-01-10 16:19:56 +0000553 except error_perm as msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000554 if msg.args[0][:3] != '500':
555 raise
Tim Peters88869f92001-01-14 23:36:06 +0000556 elif dirname == '':
557 dirname = '.' # does nothing, but could return error
558 cmd = 'CWD ' + dirname
559 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000560
Tim Peters88869f92001-01-14 23:36:06 +0000561 def size(self, filename):
562 '''Retrieve the size of a file.'''
Christian Heimes1af737c2008-01-23 08:24:23 +0000563 # The SIZE command is defined in RFC-3659
Tim Peters88869f92001-01-14 23:36:06 +0000564 resp = self.sendcmd('SIZE ' + filename)
565 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000566 s = resp[3:].strip()
567 try:
568 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000569 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000570 return int(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000571
Tim Peters88869f92001-01-14 23:36:06 +0000572 def mkd(self, dirname):
573 '''Make a directory, return its full pathname.'''
574 resp = self.sendcmd('MKD ' + dirname)
575 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000576
Tim Peters88869f92001-01-14 23:36:06 +0000577 def rmd(self, dirname):
578 '''Remove a directory.'''
579 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000580
Tim Peters88869f92001-01-14 23:36:06 +0000581 def pwd(self):
582 '''Return current working directory.'''
583 resp = self.sendcmd('PWD')
584 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000585
Tim Peters88869f92001-01-14 23:36:06 +0000586 def quit(self):
587 '''Quit, and close the connection.'''
588 resp = self.voidcmd('QUIT')
589 self.close()
590 return resp
591
592 def close(self):
593 '''Close the connection without assuming anything about it.'''
Fred Drake9c98a422001-02-28 21:46:37 +0000594 if self.file:
595 self.file.close()
596 self.sock.close()
597 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000598
599
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000600try:
601 import ssl
602except ImportError:
603 pass
604else:
605 class FTP_TLS(FTP):
606 '''A FTP subclass which adds TLS support to FTP as described
607 in RFC-4217.
608
609 Connect as usual to port 21 implicitly securing the FTP control
610 connection before authenticating.
611
612 Securing the data connection requires user to explicitly ask
613 for it by calling prot_p() method.
614
615 Usage example:
616 >>> from ftplib import FTP_TLS
617 >>> ftps = FTP_TLS('ftp.python.org')
618 >>> ftps.login() # login anonimously previously securing control channel
619 '230 Guest login ok, access restrictions apply.'
620 >>> ftps.prot_p() # switch to secure data connection
621 '200 Protection level set to P'
622 >>> ftps.retrlines('LIST') # list directory content securely
623 total 9
624 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
625 drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
626 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
627 drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
628 d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
629 drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
630 drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
631 drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
632 -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
633 '226 Transfer complete.'
634 >>> ftps.quit()
635 '221 Goodbye.'
636 >>>
637 '''
638 ssl_version = ssl.PROTOCOL_TLSv1
639
640 def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000641 certfile=None, context=None,
642 timeout=_GLOBAL_DEFAULT_TIMEOUT):
643 if context is not None and keyfile is not None:
644 raise ValueError("context and keyfile arguments are mutually "
645 "exclusive")
646 if context is not None and certfile is not None:
647 raise ValueError("context and certfile arguments are mutually "
648 "exclusive")
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000649 self.keyfile = keyfile
650 self.certfile = certfile
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000651 self.context = context
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000652 self._prot_p = False
653 FTP.__init__(self, host, user, passwd, acct, timeout)
654
655 def login(self, user='', passwd='', acct='', secure=True):
656 if secure and not isinstance(self.sock, ssl.SSLSocket):
657 self.auth()
658 return FTP.login(self, user, passwd, acct)
659
660 def auth(self):
661 '''Set up secure control connection by using TLS/SSL.'''
662 if isinstance(self.sock, ssl.SSLSocket):
663 raise ValueError("Already using TLS")
664 if self.ssl_version == ssl.PROTOCOL_TLSv1:
665 resp = self.voidcmd('AUTH TLS')
666 else:
667 resp = self.voidcmd('AUTH SSL')
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000668 if self.context is not None:
669 self.sock = self.context.wrap_socket(self.sock)
670 else:
671 self.sock = ssl.wrap_socket(self.sock, self.keyfile,
672 self.certfile,
673 ssl_version=self.ssl_version)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000674 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
675 return resp
676
677 def prot_p(self):
678 '''Set up secure data connection.'''
679 # PROT defines whether or not the data channel is to be protected.
680 # Though RFC-2228 defines four possible protection levels,
681 # RFC-4217 only recommends two, Clear and Private.
682 # Clear (PROT C) means that no security is to be used on the
683 # data-channel, Private (PROT P) means that the data-channel
684 # should be protected by TLS.
685 # PBSZ command MUST still be issued, but must have a parameter of
686 # '0' to indicate that no buffering is taking place and the data
687 # connection should not be encapsulated.
688 self.voidcmd('PBSZ 0')
689 resp = self.voidcmd('PROT P')
690 self._prot_p = True
691 return resp
692
693 def prot_c(self):
694 '''Set up clear text data connection.'''
695 resp = self.voidcmd('PROT C')
696 self._prot_p = False
697 return resp
698
699 # --- Overridden FTP methods
700
701 def ntransfercmd(self, cmd, rest=None):
702 conn, size = FTP.ntransfercmd(self, cmd, rest)
703 if self._prot_p:
Giampaolo Rodolàa67299e2010-05-26 18:06:04 +0000704 if self.context is not None:
705 conn = self.context.wrap_socket(conn)
706 else:
707 conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
708 ssl_version=self.ssl_version)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000709 return conn, size
710
711 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
712 self.voidcmd('TYPE I')
713 conn = self.transfercmd(cmd, rest)
714 try:
715 while 1:
716 data = conn.recv(blocksize)
717 if not data:
718 break
719 callback(data)
720 # shutdown ssl layer
721 if isinstance(conn, ssl.SSLSocket):
722 conn.unwrap()
723 finally:
724 conn.close()
725 return self.voidresp()
726
727 def retrlines(self, cmd, callback = None):
728 if callback is None: callback = print_line
729 resp = self.sendcmd('TYPE A')
730 conn = self.transfercmd(cmd)
731 fp = conn.makefile('r', encoding=self.encoding)
732 try:
733 while 1:
734 line = fp.readline()
735 if self.debugging > 2: print('*retr*', repr(line))
736 if not line:
737 break
738 if line[-2:] == CRLF:
739 line = line[:-2]
740 elif line[-1:] == '\n':
741 line = line[:-1]
742 callback(line)
743 # shutdown ssl layer
744 if isinstance(conn, ssl.SSLSocket):
745 conn.unwrap()
746 finally:
747 fp.close()
748 conn.close()
749 return self.voidresp()
750
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000751 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000752 self.voidcmd('TYPE I')
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000753 conn = self.transfercmd(cmd, rest)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000754 try:
755 while 1:
756 buf = fp.read(blocksize)
757 if not buf: break
758 conn.sendall(buf)
759 if callback: callback(buf)
760 # shutdown ssl layer
761 if isinstance(conn, ssl.SSLSocket):
762 conn.unwrap()
763 finally:
764 conn.close()
765 return self.voidresp()
766
767 def storlines(self, cmd, fp, callback=None):
768 self.voidcmd('TYPE A')
769 conn = self.transfercmd(cmd)
770 try:
771 while 1:
772 buf = fp.readline()
773 if not buf: break
774 if buf[-2:] != B_CRLF:
775 if buf[-1] in B_CRLF: buf = buf[:-1]
776 buf = buf + B_CRLF
777 conn.sendall(buf)
778 if callback: callback(buf)
779 # shutdown ssl layer
780 if isinstance(conn, ssl.SSLSocket):
781 conn.unwrap()
782 finally:
783 conn.close()
784 return self.voidresp()
785
786 __all__.append('FTP_TLS')
787 all_errors = (Error, IOError, EOFError, ssl.SSLError)
788
789
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000790_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000791
792def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000793 '''Parse the '150' response for a RETR request.
794 Returns the expected transfer size or None; size is not guaranteed to
795 be present in the 150 message.
796 '''
797 if resp[:3] != '150':
Collin Winterce36ad82007-08-30 01:19:48 +0000798 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000799 global _150_re
800 if _150_re is None:
801 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000802 _150_re = re.compile(
803 "150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII)
Tim Peters88869f92001-01-14 23:36:06 +0000804 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000805 if not m:
806 return None
807 s = m.group(1)
808 try:
809 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000810 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000811 return int(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000812
813
Guido van Rossum70297d32001-08-17 17:24:29 +0000814_227_re = None
815
Guido van Rossumd2560b01996-05-28 23:41:25 +0000816def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000817 '''Parse the '227' response for a PASV request.
818 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
819 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000820
Tim Peters88869f92001-01-14 23:36:06 +0000821 if resp[:3] != '227':
Collin Winterce36ad82007-08-30 01:19:48 +0000822 raise error_reply(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000823 global _227_re
824 if _227_re is None:
825 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000826 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII)
Guido van Rossum70297d32001-08-17 17:24:29 +0000827 m = _227_re.search(resp)
828 if not m:
Collin Winterce36ad82007-08-30 01:19:48 +0000829 raise error_proto(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000830 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000831 host = '.'.join(numbers[:4])
832 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000833 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000834
835
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000836def parse229(resp, peer):
837 '''Parse the '229' response for a EPSV request.
838 Raises error_proto if it does not contain '(|||port|)'
839 Return ('host.addr.as.numbers', port#) tuple.'''
840
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000841 if resp[:3] != '229':
Collin Winterce36ad82007-08-30 01:19:48 +0000842 raise error_reply(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000843 left = resp.find('(')
Collin Winterce36ad82007-08-30 01:19:48 +0000844 if left < 0: raise error_proto(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000845 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000846 if right < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000847 raise error_proto(resp) # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000848 if resp[left + 1] != resp[right - 1]:
Collin Winterce36ad82007-08-30 01:19:48 +0000849 raise error_proto(resp)
Walter Dörwalda401ae42002-06-03 10:41:45 +0000850 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000851 if len(parts) != 5:
Collin Winterce36ad82007-08-30 01:19:48 +0000852 raise error_proto(resp)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000853 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000854 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000855 return host, port
856
857
Guido van Rossumc567c601992-11-05 22:22:37 +0000858def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000859 '''Parse the '257' response for a MKD or PWD request.
860 This is a response to a MKD or PWD request: a directory name.
861 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000862
Tim Peters88869f92001-01-14 23:36:06 +0000863 if resp[:3] != '257':
Collin Winterce36ad82007-08-30 01:19:48 +0000864 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000865 if resp[3:5] != ' "':
866 return '' # Not compliant to RFC 959, but UNIX ftpd does this
867 dirname = ''
868 i = 5
869 n = len(resp)
870 while i < n:
871 c = resp[i]
872 i = i+1
873 if c == '"':
874 if i >= n or resp[i] != '"':
875 break
876 i = i+1
877 dirname = dirname + c
878 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000879
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000880
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000881def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000882 '''Default retrlines callback to print a line.'''
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000883 print(line)
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000884
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000885
Guido van Rossumd2560b01996-05-28 23:41:25 +0000886def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000887 '''Copy file from one FTP-instance to another.'''
888 if not targetname: targetname = sourcename
889 type = 'TYPE ' + type
890 source.voidcmd(type)
891 target.voidcmd(type)
892 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
893 target.sendport(sourcehost, sourceport)
894 # RFC 959: the user must "listen" [...] BEFORE sending the
895 # transfer request.
896 # So: STOR before RETR, because here the target is a "user".
897 treply = target.sendcmd('STOR ' + targetname)
898 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
899 sreply = source.sendcmd('RETR ' + sourcename)
900 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
901 source.voidresp()
902 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000903
Tim Peters88869f92001-01-14 23:36:06 +0000904
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000905class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000906 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000907
Tim Peters88869f92001-01-14 23:36:06 +0000908 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000909
Tim Peters88869f92001-01-14 23:36:06 +0000910 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000911
Tim Peters88869f92001-01-14 23:36:06 +0000912 """
913 __defuser = None
914 __defpasswd = None
915 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000916
Tim Peters88869f92001-01-14 23:36:06 +0000917 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000918 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000919 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000920 filename = os.path.join(os.environ["HOME"],
921 ".netrc")
922 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000923 raise IOError("specify file to load or set $HOME")
Tim Peters88869f92001-01-14 23:36:06 +0000924 self.__hosts = {}
925 self.__macros = {}
926 fp = open(filename, "r")
927 in_macro = 0
928 while 1:
929 line = fp.readline()
930 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000931 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000932 macro_lines.append(line)
933 continue
934 elif in_macro:
935 self.__macros[macro_name] = tuple(macro_lines)
936 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000937 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000938 host = user = passwd = acct = None
939 default = 0
940 i = 0
941 while i < len(words):
942 w1 = words[i]
943 if i+1 < len(words):
944 w2 = words[i + 1]
945 else:
946 w2 = None
947 if w1 == 'default':
948 default = 1
949 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000950 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000951 i = i + 1
952 elif w1 == 'login' and w2:
953 user = w2
954 i = i + 1
955 elif w1 == 'password' and w2:
956 passwd = w2
957 i = i + 1
958 elif w1 == 'account' and w2:
959 acct = w2
960 i = i + 1
961 elif w1 == 'macdef' and w2:
962 macro_name = w2
963 macro_lines = []
964 in_macro = 1
965 break
966 i = i + 1
967 if default:
968 self.__defuser = user or self.__defuser
969 self.__defpasswd = passwd or self.__defpasswd
970 self.__defacct = acct or self.__defacct
971 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000972 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000973 ouser, opasswd, oacct = \
974 self.__hosts[host]
975 user = user or ouser
976 passwd = passwd or opasswd
977 acct = acct or oacct
978 self.__hosts[host] = user, passwd, acct
979 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000980
Tim Peters88869f92001-01-14 23:36:06 +0000981 def get_hosts(self):
982 """Return a list of hosts mentioned in the .netrc file."""
983 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000984
Tim Peters88869f92001-01-14 23:36:06 +0000985 def get_account(self, host):
986 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000987
Tim Peters88869f92001-01-14 23:36:06 +0000988 The return value is a triple containing userid,
989 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000990
Tim Peters88869f92001-01-14 23:36:06 +0000991 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000992 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000993 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000994 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000995 user, passwd, acct = self.__hosts[host]
996 user = user or self.__defuser
997 passwd = passwd or self.__defpasswd
998 acct = acct or self.__defacct
999 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +00001000
Tim Peters88869f92001-01-14 23:36:06 +00001001 def get_macros(self):
1002 """Return a list of all defined macro names."""
1003 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +00001004
Tim Peters88869f92001-01-14 23:36:06 +00001005 def get_macro(self, macro):
1006 """Return a sequence of lines which define a named macro."""
1007 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +00001008
Fred Drake475d51d1997-06-24 22:02:54 +00001009
Tim Peters88869f92001-01-14 23:36:06 +00001010
Guido van Rossum1115ab21992-11-04 15:51:30 +00001011def test():
Tim Peters88869f92001-01-14 23:36:06 +00001012 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001013 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
1014
1015 -d dir
1016 -l list
1017 -p password
1018 '''
1019
1020 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001021 print(test.__doc__)
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001022 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +00001023
Tim Peters88869f92001-01-14 23:36:06 +00001024 debugging = 0
1025 rcfile = None
1026 while sys.argv[1] == '-d':
1027 debugging = debugging+1
1028 del sys.argv[1]
1029 if sys.argv[1][:2] == '-r':
1030 # get name of alternate ~/.netrc file:
1031 rcfile = sys.argv[1][2:]
1032 del sys.argv[1]
1033 host = sys.argv[1]
1034 ftp = FTP(host)
1035 ftp.set_debuglevel(debugging)
1036 userid = passwd = acct = ''
1037 try:
1038 netrc = Netrc(rcfile)
1039 except IOError:
1040 if rcfile is not None:
1041 sys.stderr.write("Could not open account file"
1042 " -- using anonymous login.")
1043 else:
1044 try:
1045 userid, passwd, acct = netrc.get_account(host)
1046 except KeyError:
1047 # no account for host
1048 sys.stderr.write(
1049 "No account -- using anonymous login.")
1050 ftp.login(userid, passwd, acct)
1051 for file in sys.argv[2:]:
1052 if file[:2] == '-l':
1053 ftp.dir(file[2:])
1054 elif file[:2] == '-d':
1055 cmd = 'CWD'
1056 if file[2:]: cmd = cmd + ' ' + file[2:]
1057 resp = ftp.sendcmd(cmd)
1058 elif file == '-p':
1059 ftp.set_pasv(not ftp.passiveserver)
1060 else:
1061 ftp.retrbinary('RETR ' + file, \
1062 sys.stdout.write, 1024)
1063 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +00001064
1065
1066if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +00001067 test()