blob: c25ae2afbb10159200c5a4b0277028bf2ea3d85b [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,
641 certfile=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
642 self.keyfile = keyfile
643 self.certfile = certfile
644 self._prot_p = False
645 FTP.__init__(self, host, user, passwd, acct, timeout)
646
647 def login(self, user='', passwd='', acct='', secure=True):
648 if secure and not isinstance(self.sock, ssl.SSLSocket):
649 self.auth()
650 return FTP.login(self, user, passwd, acct)
651
652 def auth(self):
653 '''Set up secure control connection by using TLS/SSL.'''
654 if isinstance(self.sock, ssl.SSLSocket):
655 raise ValueError("Already using TLS")
656 if self.ssl_version == ssl.PROTOCOL_TLSv1:
657 resp = self.voidcmd('AUTH TLS')
658 else:
659 resp = self.voidcmd('AUTH SSL')
660 self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile,
661 ssl_version=self.ssl_version)
662 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
663 return resp
664
665 def prot_p(self):
666 '''Set up secure data connection.'''
667 # PROT defines whether or not the data channel is to be protected.
668 # Though RFC-2228 defines four possible protection levels,
669 # RFC-4217 only recommends two, Clear and Private.
670 # Clear (PROT C) means that no security is to be used on the
671 # data-channel, Private (PROT P) means that the data-channel
672 # should be protected by TLS.
673 # PBSZ command MUST still be issued, but must have a parameter of
674 # '0' to indicate that no buffering is taking place and the data
675 # connection should not be encapsulated.
676 self.voidcmd('PBSZ 0')
677 resp = self.voidcmd('PROT P')
678 self._prot_p = True
679 return resp
680
681 def prot_c(self):
682 '''Set up clear text data connection.'''
683 resp = self.voidcmd('PROT C')
684 self._prot_p = False
685 return resp
686
687 # --- Overridden FTP methods
688
689 def ntransfercmd(self, cmd, rest=None):
690 conn, size = FTP.ntransfercmd(self, cmd, rest)
691 if self._prot_p:
692 conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
693 ssl_version=self.ssl_version)
694 return conn, size
695
696 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
697 self.voidcmd('TYPE I')
698 conn = self.transfercmd(cmd, rest)
699 try:
700 while 1:
701 data = conn.recv(blocksize)
702 if not data:
703 break
704 callback(data)
705 # shutdown ssl layer
706 if isinstance(conn, ssl.SSLSocket):
707 conn.unwrap()
708 finally:
709 conn.close()
710 return self.voidresp()
711
712 def retrlines(self, cmd, callback = None):
713 if callback is None: callback = print_line
714 resp = self.sendcmd('TYPE A')
715 conn = self.transfercmd(cmd)
716 fp = conn.makefile('r', encoding=self.encoding)
717 try:
718 while 1:
719 line = fp.readline()
720 if self.debugging > 2: print('*retr*', repr(line))
721 if not line:
722 break
723 if line[-2:] == CRLF:
724 line = line[:-2]
725 elif line[-1:] == '\n':
726 line = line[:-1]
727 callback(line)
728 # shutdown ssl layer
729 if isinstance(conn, ssl.SSLSocket):
730 conn.unwrap()
731 finally:
732 fp.close()
733 conn.close()
734 return self.voidresp()
735
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000736 def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000737 self.voidcmd('TYPE I')
Antoine Pitrou648bcd72009-11-27 13:23:26 +0000738 conn = self.transfercmd(cmd, rest)
Antoine Pitrouf988cd02009-11-17 20:21:14 +0000739 try:
740 while 1:
741 buf = fp.read(blocksize)
742 if not buf: break
743 conn.sendall(buf)
744 if callback: callback(buf)
745 # shutdown ssl layer
746 if isinstance(conn, ssl.SSLSocket):
747 conn.unwrap()
748 finally:
749 conn.close()
750 return self.voidresp()
751
752 def storlines(self, cmd, fp, callback=None):
753 self.voidcmd('TYPE A')
754 conn = self.transfercmd(cmd)
755 try:
756 while 1:
757 buf = fp.readline()
758 if not buf: break
759 if buf[-2:] != B_CRLF:
760 if buf[-1] in B_CRLF: buf = buf[:-1]
761 buf = buf + B_CRLF
762 conn.sendall(buf)
763 if callback: callback(buf)
764 # shutdown ssl layer
765 if isinstance(conn, ssl.SSLSocket):
766 conn.unwrap()
767 finally:
768 conn.close()
769 return self.voidresp()
770
771 __all__.append('FTP_TLS')
772 all_errors = (Error, IOError, EOFError, ssl.SSLError)
773
774
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000775_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000776
777def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000778 '''Parse the '150' response for a RETR request.
779 Returns the expected transfer size or None; size is not guaranteed to
780 be present in the 150 message.
781 '''
782 if resp[:3] != '150':
Collin Winterce36ad82007-08-30 01:19:48 +0000783 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000784 global _150_re
785 if _150_re is None:
786 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000787 _150_re = re.compile(
788 "150 .* \((\d+) bytes\)", re.IGNORECASE | re.ASCII)
Tim Peters88869f92001-01-14 23:36:06 +0000789 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000790 if not m:
791 return None
792 s = m.group(1)
793 try:
794 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000795 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000796 return int(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000797
798
Guido van Rossum70297d32001-08-17 17:24:29 +0000799_227_re = None
800
Guido van Rossumd2560b01996-05-28 23:41:25 +0000801def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000802 '''Parse the '227' response for a PASV request.
803 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
804 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000805
Tim Peters88869f92001-01-14 23:36:06 +0000806 if resp[:3] != '227':
Collin Winterce36ad82007-08-30 01:19:48 +0000807 raise error_reply(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000808 global _227_re
809 if _227_re is None:
810 import re
Antoine Pitroufd036452008-08-19 17:56:33 +0000811 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)', re.ASCII)
Guido van Rossum70297d32001-08-17 17:24:29 +0000812 m = _227_re.search(resp)
813 if not m:
Collin Winterce36ad82007-08-30 01:19:48 +0000814 raise error_proto(resp)
Guido van Rossum70297d32001-08-17 17:24:29 +0000815 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000816 host = '.'.join(numbers[:4])
817 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000818 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000819
820
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000821def parse229(resp, peer):
822 '''Parse the '229' response for a EPSV request.
823 Raises error_proto if it does not contain '(|||port|)'
824 Return ('host.addr.as.numbers', port#) tuple.'''
825
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000826 if resp[:3] != '229':
Collin Winterce36ad82007-08-30 01:19:48 +0000827 raise error_reply(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000828 left = resp.find('(')
Collin Winterce36ad82007-08-30 01:19:48 +0000829 if left < 0: raise error_proto(resp)
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000830 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000831 if right < 0:
Collin Winterce36ad82007-08-30 01:19:48 +0000832 raise error_proto(resp) # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000833 if resp[left + 1] != resp[right - 1]:
Collin Winterce36ad82007-08-30 01:19:48 +0000834 raise error_proto(resp)
Walter Dörwalda401ae42002-06-03 10:41:45 +0000835 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000836 if len(parts) != 5:
Collin Winterce36ad82007-08-30 01:19:48 +0000837 raise error_proto(resp)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000838 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000839 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000840 return host, port
841
842
Guido van Rossumc567c601992-11-05 22:22:37 +0000843def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000844 '''Parse the '257' response for a MKD or PWD request.
845 This is a response to a MKD or PWD request: a directory name.
846 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000847
Tim Peters88869f92001-01-14 23:36:06 +0000848 if resp[:3] != '257':
Collin Winterce36ad82007-08-30 01:19:48 +0000849 raise error_reply(resp)
Tim Peters88869f92001-01-14 23:36:06 +0000850 if resp[3:5] != ' "':
851 return '' # Not compliant to RFC 959, but UNIX ftpd does this
852 dirname = ''
853 i = 5
854 n = len(resp)
855 while i < n:
856 c = resp[i]
857 i = i+1
858 if c == '"':
859 if i >= n or resp[i] != '"':
860 break
861 i = i+1
862 dirname = dirname + c
863 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000864
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000865
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000866def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000867 '''Default retrlines callback to print a line.'''
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000868 print(line)
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000869
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000870
Guido van Rossumd2560b01996-05-28 23:41:25 +0000871def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000872 '''Copy file from one FTP-instance to another.'''
873 if not targetname: targetname = sourcename
874 type = 'TYPE ' + type
875 source.voidcmd(type)
876 target.voidcmd(type)
877 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
878 target.sendport(sourcehost, sourceport)
879 # RFC 959: the user must "listen" [...] BEFORE sending the
880 # transfer request.
881 # So: STOR before RETR, because here the target is a "user".
882 treply = target.sendcmd('STOR ' + targetname)
883 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
884 sreply = source.sendcmd('RETR ' + sourcename)
885 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
886 source.voidresp()
887 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000888
Tim Peters88869f92001-01-14 23:36:06 +0000889
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000890class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000891 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000892
Tim Peters88869f92001-01-14 23:36:06 +0000893 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000894
Tim Peters88869f92001-01-14 23:36:06 +0000895 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000896
Tim Peters88869f92001-01-14 23:36:06 +0000897 """
898 __defuser = None
899 __defpasswd = None
900 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000901
Tim Peters88869f92001-01-14 23:36:06 +0000902 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000903 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000904 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000905 filename = os.path.join(os.environ["HOME"],
906 ".netrc")
907 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000908 raise IOError("specify file to load or set $HOME")
Tim Peters88869f92001-01-14 23:36:06 +0000909 self.__hosts = {}
910 self.__macros = {}
911 fp = open(filename, "r")
912 in_macro = 0
913 while 1:
914 line = fp.readline()
915 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000916 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000917 macro_lines.append(line)
918 continue
919 elif in_macro:
920 self.__macros[macro_name] = tuple(macro_lines)
921 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000922 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000923 host = user = passwd = acct = None
924 default = 0
925 i = 0
926 while i < len(words):
927 w1 = words[i]
928 if i+1 < len(words):
929 w2 = words[i + 1]
930 else:
931 w2 = None
932 if w1 == 'default':
933 default = 1
934 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000935 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000936 i = i + 1
937 elif w1 == 'login' and w2:
938 user = w2
939 i = i + 1
940 elif w1 == 'password' and w2:
941 passwd = w2
942 i = i + 1
943 elif w1 == 'account' and w2:
944 acct = w2
945 i = i + 1
946 elif w1 == 'macdef' and w2:
947 macro_name = w2
948 macro_lines = []
949 in_macro = 1
950 break
951 i = i + 1
952 if default:
953 self.__defuser = user or self.__defuser
954 self.__defpasswd = passwd or self.__defpasswd
955 self.__defacct = acct or self.__defacct
956 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000957 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000958 ouser, opasswd, oacct = \
959 self.__hosts[host]
960 user = user or ouser
961 passwd = passwd or opasswd
962 acct = acct or oacct
963 self.__hosts[host] = user, passwd, acct
964 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000965
Tim Peters88869f92001-01-14 23:36:06 +0000966 def get_hosts(self):
967 """Return a list of hosts mentioned in the .netrc file."""
968 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000969
Tim Peters88869f92001-01-14 23:36:06 +0000970 def get_account(self, host):
971 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000972
Tim Peters88869f92001-01-14 23:36:06 +0000973 The return value is a triple containing userid,
974 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000975
Tim Peters88869f92001-01-14 23:36:06 +0000976 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000977 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000978 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000979 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000980 user, passwd, acct = self.__hosts[host]
981 user = user or self.__defuser
982 passwd = passwd or self.__defpasswd
983 acct = acct or self.__defacct
984 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +0000985
Tim Peters88869f92001-01-14 23:36:06 +0000986 def get_macros(self):
987 """Return a list of all defined macro names."""
988 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000989
Tim Peters88869f92001-01-14 23:36:06 +0000990 def get_macro(self, macro):
991 """Return a sequence of lines which define a named macro."""
992 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000993
Fred Drake475d51d1997-06-24 22:02:54 +0000994
Tim Peters88869f92001-01-14 23:36:06 +0000995
Guido van Rossum1115ab21992-11-04 15:51:30 +0000996def test():
Tim Peters88869f92001-01-14 23:36:06 +0000997 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000998 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
999
1000 -d dir
1001 -l list
1002 -p password
1003 '''
1004
1005 if len(sys.argv) < 2:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001006 print(test.__doc__)
Raymond Hettingerc88a6c72005-04-05 04:31:09 +00001007 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +00001008
Tim Peters88869f92001-01-14 23:36:06 +00001009 debugging = 0
1010 rcfile = None
1011 while sys.argv[1] == '-d':
1012 debugging = debugging+1
1013 del sys.argv[1]
1014 if sys.argv[1][:2] == '-r':
1015 # get name of alternate ~/.netrc file:
1016 rcfile = sys.argv[1][2:]
1017 del sys.argv[1]
1018 host = sys.argv[1]
1019 ftp = FTP(host)
1020 ftp.set_debuglevel(debugging)
1021 userid = passwd = acct = ''
1022 try:
1023 netrc = Netrc(rcfile)
1024 except IOError:
1025 if rcfile is not None:
1026 sys.stderr.write("Could not open account file"
1027 " -- using anonymous login.")
1028 else:
1029 try:
1030 userid, passwd, acct = netrc.get_account(host)
1031 except KeyError:
1032 # no account for host
1033 sys.stderr.write(
1034 "No account -- using anonymous login.")
1035 ftp.login(userid, passwd, acct)
1036 for file in sys.argv[2:]:
1037 if file[:2] == '-l':
1038 ftp.dir(file[2:])
1039 elif file[:2] == '-d':
1040 cmd = 'CWD'
1041 if file[2:]: cmd = cmd + ' ' + file[2:]
1042 resp = ftp.sendcmd(cmd)
1043 elif file == '-p':
1044 ftp.set_pasv(not ftp.passiveserver)
1045 else:
1046 ftp.retrbinary('RETR ' + file, \
1047 sys.stdout.write, 1024)
1048 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +00001049
1050
1051if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +00001052 test()