blob: 23ccd88b1b108cfd516f39600dd230d56e72f96d [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.
35#
Guido van Rossumc567c601992-11-05 22:22:37 +000036
Guido van Rossum1115ab21992-11-04 15:51:30 +000037import os
38import sys
Guido van Rossum1115ab21992-11-04 15:51:30 +000039
Guido van Rossumb6775db1994-08-01 11:34:53 +000040# Import SOCKS module if it exists, else standard socket module socket
41try:
Tim Peters88869f92001-01-14 23:36:06 +000042 import SOCKS; socket = SOCKS; del SOCKS # import SOCKS as socket
43 from socket import getfqdn; socket.getfqdn = getfqdn; del getfqdn
Guido van Rossumb6775db1994-08-01 11:34:53 +000044except ImportError:
Tim Peters88869f92001-01-14 23:36:06 +000045 import socket
Guido van Rossumb6775db1994-08-01 11:34:53 +000046
Skip Montanaroeccd02a2001-01-20 23:34:12 +000047__all__ = ["FTP","Netrc"]
Guido van Rossum1115ab21992-11-04 15:51:30 +000048
Guido van Rossumd3166071993-05-24 14:16:22 +000049# Magic number from <socket.h>
Tim Peters88869f92001-01-14 23:36:06 +000050MSG_OOB = 0x1 # Process data out of band
Guido van Rossumd3166071993-05-24 14:16:22 +000051
52
Guido van Rossumc567c601992-11-05 22:22:37 +000053# The standard FTP server control port
Guido van Rossum1115ab21992-11-04 15:51:30 +000054FTP_PORT = 21
Guido van Rossum1115ab21992-11-04 15:51:30 +000055
56
Guido van Rossum21974791992-11-06 13:34:17 +000057# Exception raised when an error or invalid response is received
Fred Drake227b1202000-08-17 05:06:49 +000058class Error(Exception): pass
Tim Peters88869f92001-01-14 23:36:06 +000059class error_reply(Error): pass # unexpected [123]xx reply
60class error_temp(Error): pass # 4xx errors
61class error_perm(Error): pass # 5xx errors
62class error_proto(Error): pass # response does not begin with [1-5]
Guido van Rossum1115ab21992-11-04 15:51:30 +000063
64
Guido van Rossum21974791992-11-06 13:34:17 +000065# All exceptions (hopefully) that may be raised here and that aren't
66# (always) programming errors on our side
Fred Drake227b1202000-08-17 05:06:49 +000067all_errors = (Error, socket.error, IOError, EOFError)
Guido van Rossum21974791992-11-06 13:34:17 +000068
69
Guido van Rossum1115ab21992-11-04 15:51:30 +000070# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
71CRLF = '\r\n'
72
73
Guido van Rossum1115ab21992-11-04 15:51:30 +000074# The class itself
75class FTP:
76
Tim Peters88869f92001-01-14 23:36:06 +000077 '''An FTP client class.
Guido van Rossumd2560b01996-05-28 23:41:25 +000078
Tim Peters88869f92001-01-14 23:36:06 +000079 To create a connection, call the class using these argument:
80 host, user, passwd, acct
81 These are all strings, and have default value ''.
82 Then use self.connect() with optional host and port argument.
Guido van Rossumd2560b01996-05-28 23:41:25 +000083
Tim Peters88869f92001-01-14 23:36:06 +000084 To download a file, use ftp.retrlines('RETR ' + filename),
85 or ftp.retrbinary() with slightly different arguments.
86 To upload a file, use ftp.storlines() or ftp.storbinary(),
87 which have an open file as argument (see their definitions
88 below for details).
89 The download/upload functions first issue appropriate TYPE
90 and PORT or PASV commands.
Guido van Rossumd2560b01996-05-28 23:41:25 +000091'''
92
Fred Drake9c98a422001-02-28 21:46:37 +000093 debugging = 0
94 host = ''
95 port = FTP_PORT
96 sock = None
97 file = None
98 welcome = None
99 passiveserver = 1
100
Tim Peters88869f92001-01-14 23:36:06 +0000101 # Initialization method (called by class instantiation).
102 # Initialize host to localhost, port to standard ftp port
103 # Optional arguments are host (for connect()),
104 # and user, passwd, acct (for login())
Fred Drake9c98a422001-02-28 21:46:37 +0000105 def __init__(self, host='', user='', passwd='', acct=''):
Tim Peters88869f92001-01-14 23:36:06 +0000106 if host:
Fred Drake9c98a422001-02-28 21:46:37 +0000107 self.connect(host)
108 if user: self.login(user, passwd, acct)
Guido van Rossum52fc1f61993-06-17 12:38:10 +0000109
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000110 def connect(self, host = '', port = 0):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000111 '''Connect to host. Arguments are:
112 - host: hostname to connect to (string, default previous host)
113 - port: port to connect to (integer, default previous port)'''
114 if host: self.host = host
115 if port: self.port = port
Martin v. Löwis2ad25692001-07-31 08:40:21 +0000116 msg = "getaddrinfo returns an empty list"
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000117 for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
118 af, socktype, proto, canonname, sa = res
119 try:
120 self.sock = socket.socket(af, socktype, proto)
121 self.sock.connect(sa)
Guido van Rossum56be3b12007-01-14 18:43:49 +0000122 except socket.error as err:
123 msg = err
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000124 if self.sock:
125 self.sock.close()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000126 self.sock = None
127 continue
128 break
129 if not self.sock:
130 raise socket.error, msg
131 self.af = af
132 self.file = self.sock.makefile('rb')
133 self.welcome = self.getresp()
134 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000135
Tim Peters88869f92001-01-14 23:36:06 +0000136 def getwelcome(self):
137 '''Get the welcome message from the server.
138 (this is read and squirreled away by connect())'''
139 if self.debugging:
140 print '*welcome*', self.sanitize(self.welcome)
141 return self.welcome
Guido van Rossum1115ab21992-11-04 15:51:30 +0000142
Tim Peters88869f92001-01-14 23:36:06 +0000143 def set_debuglevel(self, level):
144 '''Set the debugging level.
145 The required argument level means:
146 0: no debugging output (default)
147 1: print commands and responses but not body text etc.
148 2: also print raw lines read and sent before stripping CR/LF'''
149 self.debugging = level
150 debug = set_debuglevel
Guido van Rossum1115ab21992-11-04 15:51:30 +0000151
Tim Peters88869f92001-01-14 23:36:06 +0000152 def set_pasv(self, val):
153 '''Use passive or active mode for data transfers.
154 With a false argument, use the normal PORT mode,
155 With a true argument, use the PASV command.'''
156 self.passiveserver = val
Guido van Rossumd2560b01996-05-28 23:41:25 +0000157
Tim Peters88869f92001-01-14 23:36:06 +0000158 # Internal: "sanitize" a string for printing
159 def sanitize(self, s):
160 if s[:5] == 'pass ' or s[:5] == 'PASS ':
161 i = len(s)
162 while i > 5 and s[i-1] in '\r\n':
163 i = i-1
164 s = s[:5] + '*'*(i-5) + s[i:]
Walter Dörwald70a6b492004-02-12 17:35:32 +0000165 return repr(s)
Guido van Rossumebaf1041995-05-05 15:54:14 +0000166
Tim Peters88869f92001-01-14 23:36:06 +0000167 # Internal: send one line to the server, appending CRLF
168 def putline(self, line):
169 line = line + CRLF
170 if self.debugging > 1: print '*put*', self.sanitize(line)
Martin v. Löwise12454f2002-02-16 23:06:19 +0000171 self.sock.sendall(line)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000172
Tim Peters88869f92001-01-14 23:36:06 +0000173 # Internal: send one command to the server (through putline())
174 def putcmd(self, line):
175 if self.debugging: print '*cmd*', self.sanitize(line)
176 self.putline(line)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000177
Tim Peters88869f92001-01-14 23:36:06 +0000178 # Internal: return one line from the server, stripping CRLF.
179 # Raise EOFError if the connection is closed
180 def getline(self):
181 line = self.file.readline()
182 if self.debugging > 1:
183 print '*get*', self.sanitize(line)
184 if not line: raise EOFError
185 if line[-2:] == CRLF: line = line[:-2]
186 elif line[-1:] in CRLF: line = line[:-1]
187 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000188
Tim Peters88869f92001-01-14 23:36:06 +0000189 # Internal: get a response from the server, which may possibly
190 # consist of multiple lines. Return a single string with no
191 # trailing CRLF. If the response consists of multiple lines,
192 # these are separated by '\n' characters in the string
193 def getmultiline(self):
194 line = self.getline()
195 if line[3:4] == '-':
196 code = line[:3]
197 while 1:
198 nextline = self.getline()
199 line = line + ('\n' + nextline)
200 if nextline[:3] == code and \
201 nextline[3:4] != '-':
202 break
203 return line
Guido van Rossum1115ab21992-11-04 15:51:30 +0000204
Tim Peters88869f92001-01-14 23:36:06 +0000205 # Internal: get a response from the server.
206 # Raise various errors if the response indicates an error
207 def getresp(self):
208 resp = self.getmultiline()
209 if self.debugging: print '*resp*', self.sanitize(resp)
210 self.lastresp = resp[:3]
211 c = resp[:1]
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000212 if c in ('1', '2', '3'):
213 return resp
Tim Peters88869f92001-01-14 23:36:06 +0000214 if c == '4':
215 raise error_temp, resp
216 if c == '5':
217 raise error_perm, resp
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000218 raise error_proto, resp
Guido van Rossum1115ab21992-11-04 15:51:30 +0000219
Tim Peters88869f92001-01-14 23:36:06 +0000220 def voidresp(self):
221 """Expect a response beginning with '2'."""
222 resp = self.getresp()
223 if resp[0] != '2':
224 raise error_reply, resp
225 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000226
Tim Peters88869f92001-01-14 23:36:06 +0000227 def abort(self):
228 '''Abort a file transfer. Uses out-of-band data.
229 This does not follow the procedure from the RFC to send Telnet
230 IP and Synch; that doesn't seem to work with the servers I've
231 tried. Instead, just send the ABOR command as OOB data.'''
232 line = 'ABOR' + CRLF
233 if self.debugging > 1: print '*put urgent*', self.sanitize(line)
Martin v. Löwise12454f2002-02-16 23:06:19 +0000234 self.sock.sendall(line, MSG_OOB)
Tim Peters88869f92001-01-14 23:36:06 +0000235 resp = self.getmultiline()
236 if resp[:3] not in ('426', '226'):
237 raise error_proto, resp
Guido van Rossumd3166071993-05-24 14:16:22 +0000238
Tim Peters88869f92001-01-14 23:36:06 +0000239 def sendcmd(self, cmd):
240 '''Send a command and return the response.'''
241 self.putcmd(cmd)
242 return self.getresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000243
Tim Peters88869f92001-01-14 23:36:06 +0000244 def voidcmd(self, cmd):
245 """Send a command and expect a response beginning with '2'."""
246 self.putcmd(cmd)
247 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000248
Tim Peters88869f92001-01-14 23:36:06 +0000249 def sendport(self, host, port):
250 '''Send a PORT command with the current host and the given
251 port number.
252 '''
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000253 hbytes = host.split('.')
Walter Dörwald70a6b492004-02-12 17:35:32 +0000254 pbytes = [repr(port/256), repr(port%256)]
Tim Peters88869f92001-01-14 23:36:06 +0000255 bytes = hbytes + pbytes
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000256 cmd = 'PORT ' + ','.join(bytes)
Tim Peters88869f92001-01-14 23:36:06 +0000257 return self.voidcmd(cmd)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000258
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000259 def sendeprt(self, host, port):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000260 '''Send a EPRT command with the current host and the given port number.'''
261 af = 0
262 if self.af == socket.AF_INET:
263 af = 1
264 if self.af == socket.AF_INET6:
265 af = 2
266 if af == 0:
267 raise error_proto, 'unsupported address family'
Walter Dörwald70a6b492004-02-12 17:35:32 +0000268 fields = ['', repr(af), host, repr(port), '']
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000269 cmd = 'EPRT ' + '|'.join(fields)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000270 return self.voidcmd(cmd)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000271
Tim Peters88869f92001-01-14 23:36:06 +0000272 def makeport(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000273 '''Create a new socket and send a PORT command for it.'''
Martin v. Löwis2ad25692001-07-31 08:40:21 +0000274 msg = "getaddrinfo returns an empty list"
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000275 sock = None
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000276 for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
277 af, socktype, proto, canonname, sa = res
278 try:
279 sock = socket.socket(af, socktype, proto)
280 sock.bind(sa)
Guido van Rossumb940e112007-01-10 16:19:56 +0000281 except socket.error as msg:
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000282 if sock:
283 sock.close()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000284 sock = None
285 continue
286 break
287 if not sock:
288 raise socket.error, msg
289 sock.listen(1)
290 port = sock.getsockname()[1] # Get proper port
291 host = self.sock.getsockname()[0] # Get proper host
292 if self.af == socket.AF_INET:
293 resp = self.sendport(host, port)
294 else:
295 resp = self.sendeprt(host, port)
296 return sock
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000297
298 def makepasv(self):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000299 if self.af == socket.AF_INET:
300 host, port = parse227(self.sendcmd('PASV'))
301 else:
302 host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
303 return host, port
Guido van Rossum1115ab21992-11-04 15:51:30 +0000304
Tim Peters88869f92001-01-14 23:36:06 +0000305 def ntransfercmd(self, cmd, rest=None):
306 """Initiate a transfer over the data connection.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000307
Tim Peters88869f92001-01-14 23:36:06 +0000308 If the transfer is active, send a port command and the
309 transfer command, and accept the connection. If the server is
310 passive, send a pasv command, connect to it, and start the
311 transfer command. Either way, return the socket for the
312 connection and the expected size of the transfer. The
313 expected size may be None if it could not be determined.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000314
Tim Peters88869f92001-01-14 23:36:06 +0000315 Optional `rest' argument can be a string that is sent as the
316 argument to a RESTART command. This is essentially a server
317 marker used to tell the server to skip over any data up to the
318 given marker.
319 """
320 size = None
321 if self.passiveserver:
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000322 host, port = self.makepasv()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000323 af, socktype, proto, canon, sa = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0]
324 conn = socket.socket(af, socktype, proto)
325 conn.connect(sa)
Tim Peters88869f92001-01-14 23:36:06 +0000326 if rest is not None:
327 self.sendcmd("REST %s" % rest)
328 resp = self.sendcmd(cmd)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000329 # Some servers apparently send a 200 reply to
330 # a LIST or STOR command, before the 150 reply
331 # (and way before the 226 reply). This seems to
332 # be in violation of the protocol (which only allows
333 # 1xx or error messages for LIST), so we just discard
334 # this response.
335 if resp[0] == '2':
336 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000337 if resp[0] != '1':
338 raise error_reply, resp
339 else:
340 sock = self.makeport()
341 if rest is not None:
342 self.sendcmd("REST %s" % rest)
343 resp = self.sendcmd(cmd)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000344 # See above.
345 if resp[0] == '2':
346 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000347 if resp[0] != '1':
348 raise error_reply, resp
349 conn, sockaddr = sock.accept()
350 if resp[:3] == '150':
351 # this is conditional in case we received a 125
352 size = parse150(resp)
353 return conn, size
Fred Drake4de02d91997-01-10 18:26:09 +0000354
Tim Peters88869f92001-01-14 23:36:06 +0000355 def transfercmd(self, cmd, rest=None):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000356 """Like ntransfercmd() but returns only the socket."""
Tim Peters88869f92001-01-14 23:36:06 +0000357 return self.ntransfercmd(cmd, rest)[0]
Guido van Rossumc567c601992-11-05 22:22:37 +0000358
Tim Peters88869f92001-01-14 23:36:06 +0000359 def login(self, user = '', passwd = '', acct = ''):
360 '''Login, default anonymous.'''
361 if not user: user = 'anonymous'
362 if not passwd: passwd = ''
363 if not acct: acct = ''
364 if user == 'anonymous' and passwd in ('', '-'):
Tim Peterse4418602002-02-16 07:34:19 +0000365 # If there is no anonymous ftp password specified
366 # then we'll just use anonymous@
367 # We don't send any other thing because:
368 # - We want to remain anonymous
369 # - We want to stop SPAM
370 # - We don't want to let ftp sites to discriminate by the user,
371 # host or country.
Guido van Rossumc33e0772001-12-28 20:54:28 +0000372 passwd = passwd + 'anonymous@'
Tim Peters88869f92001-01-14 23:36:06 +0000373 resp = self.sendcmd('USER ' + user)
374 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
375 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
376 if resp[0] != '2':
377 raise error_reply, resp
378 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000379
Tim Peters88869f92001-01-14 23:36:06 +0000380 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
381 """Retrieve data in binary mode.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000382
Tim Peters88869f92001-01-14 23:36:06 +0000383 `cmd' is a RETR command. `callback' is a callback function is
384 called for each block. No more than `blocksize' number of
385 bytes will be read from the socket. Optional `rest' is passed
386 to transfercmd().
Guido van Rossum1115ab21992-11-04 15:51:30 +0000387
Tim Peters88869f92001-01-14 23:36:06 +0000388 A new port is created for you. Return the response code.
389 """
390 self.voidcmd('TYPE I')
391 conn = self.transfercmd(cmd, rest)
392 while 1:
393 data = conn.recv(blocksize)
394 if not data:
395 break
396 callback(data)
397 conn.close()
398 return self.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000399
Tim Peters88869f92001-01-14 23:36:06 +0000400 def retrlines(self, cmd, callback = None):
401 '''Retrieve data in line mode.
402 The argument is a RETR or LIST command.
403 The callback function (2nd argument) is called for each line,
404 with trailing CRLF stripped. This creates a new port for you.
405 print_line() is the default callback.'''
Raymond Hettingere874fc32002-05-12 05:53:51 +0000406 if callback is None: callback = print_line
Tim Peters88869f92001-01-14 23:36:06 +0000407 resp = self.sendcmd('TYPE A')
408 conn = self.transfercmd(cmd)
409 fp = conn.makefile('rb')
410 while 1:
411 line = fp.readline()
Walter Dörwald70a6b492004-02-12 17:35:32 +0000412 if self.debugging > 2: print '*retr*', repr(line)
Tim Peters88869f92001-01-14 23:36:06 +0000413 if not line:
414 break
415 if line[-2:] == CRLF:
416 line = line[:-2]
417 elif line[-1:] == '\n':
418 line = line[:-1]
419 callback(line)
420 fp.close()
421 conn.close()
422 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000423
Guido van Rossum4ac83472001-02-15 13:50:36 +0000424 def storbinary(self, cmd, fp, blocksize=8192):
Tim Peters88869f92001-01-14 23:36:06 +0000425 '''Store a file in binary mode.'''
426 self.voidcmd('TYPE I')
427 conn = self.transfercmd(cmd)
428 while 1:
429 buf = fp.read(blocksize)
430 if not buf: break
Martin v. Löwise12454f2002-02-16 23:06:19 +0000431 conn.sendall(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000432 conn.close()
433 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000434
Tim Peters88869f92001-01-14 23:36:06 +0000435 def storlines(self, cmd, fp):
436 '''Store a file in line mode.'''
437 self.voidcmd('TYPE A')
438 conn = self.transfercmd(cmd)
439 while 1:
440 buf = fp.readline()
441 if not buf: break
442 if buf[-2:] != CRLF:
443 if buf[-1] in CRLF: buf = buf[:-1]
444 buf = buf + CRLF
Martin v. Löwise12454f2002-02-16 23:06:19 +0000445 conn.sendall(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000446 conn.close()
447 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000448
Tim Peters88869f92001-01-14 23:36:06 +0000449 def acct(self, password):
450 '''Send new account name.'''
451 cmd = 'ACCT ' + password
452 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000453
Tim Peters88869f92001-01-14 23:36:06 +0000454 def nlst(self, *args):
455 '''Return a list of files in a given directory (default the current).'''
456 cmd = 'NLST'
457 for arg in args:
458 cmd = cmd + (' ' + arg)
459 files = []
460 self.retrlines(cmd, files.append)
461 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000462
Tim Peters88869f92001-01-14 23:36:06 +0000463 def dir(self, *args):
464 '''List a directory in long form.
465 By default list current directory to stdout.
466 Optional last argument is callback function; all
467 non-empty arguments before it are concatenated to the
468 LIST command. (This *should* only be used for a pathname.)'''
469 cmd = 'LIST'
470 func = None
471 if args[-1:] and type(args[-1]) != type(''):
472 args, func = args[:-1], args[-1]
473 for arg in args:
474 if arg:
475 cmd = cmd + (' ' + arg)
476 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000477
Tim Peters88869f92001-01-14 23:36:06 +0000478 def rename(self, fromname, toname):
479 '''Rename a file.'''
480 resp = self.sendcmd('RNFR ' + fromname)
481 if resp[0] != '3':
482 raise error_reply, resp
483 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000484
Tim Peters88869f92001-01-14 23:36:06 +0000485 def delete(self, filename):
486 '''Delete a file.'''
487 resp = self.sendcmd('DELE ' + filename)
488 if resp[:3] in ('250', '200'):
489 return resp
490 elif resp[:1] == '5':
491 raise error_perm, resp
492 else:
493 raise error_reply, resp
Guido van Rossum02cf5821993-05-17 08:00:02 +0000494
Tim Peters88869f92001-01-14 23:36:06 +0000495 def cwd(self, dirname):
496 '''Change to a directory.'''
497 if dirname == '..':
498 try:
499 return self.voidcmd('CDUP')
Guido van Rossumb940e112007-01-10 16:19:56 +0000500 except error_perm as msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000501 if msg.args[0][:3] != '500':
502 raise
Tim Peters88869f92001-01-14 23:36:06 +0000503 elif dirname == '':
504 dirname = '.' # does nothing, but could return error
505 cmd = 'CWD ' + dirname
506 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000507
Tim Peters88869f92001-01-14 23:36:06 +0000508 def size(self, filename):
509 '''Retrieve the size of a file.'''
510 # Note that the RFC doesn't say anything about 'SIZE'
511 resp = self.sendcmd('SIZE ' + filename)
512 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000513 s = resp[3:].strip()
514 try:
515 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000516 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000517 return int(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000518
Tim Peters88869f92001-01-14 23:36:06 +0000519 def mkd(self, dirname):
520 '''Make a directory, return its full pathname.'''
521 resp = self.sendcmd('MKD ' + dirname)
522 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000523
Tim Peters88869f92001-01-14 23:36:06 +0000524 def rmd(self, dirname):
525 '''Remove a directory.'''
526 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000527
Tim Peters88869f92001-01-14 23:36:06 +0000528 def pwd(self):
529 '''Return current working directory.'''
530 resp = self.sendcmd('PWD')
531 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000532
Tim Peters88869f92001-01-14 23:36:06 +0000533 def quit(self):
534 '''Quit, and close the connection.'''
535 resp = self.voidcmd('QUIT')
536 self.close()
537 return resp
538
539 def close(self):
540 '''Close the connection without assuming anything about it.'''
Fred Drake9c98a422001-02-28 21:46:37 +0000541 if self.file:
542 self.file.close()
543 self.sock.close()
544 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000545
546
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000547_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000548
549def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000550 '''Parse the '150' response for a RETR request.
551 Returns the expected transfer size or None; size is not guaranteed to
552 be present in the 150 message.
553 '''
554 if resp[:3] != '150':
555 raise error_reply, resp
556 global _150_re
557 if _150_re is None:
558 import re
559 _150_re = re.compile("150 .* \((\d+) bytes\)", re.IGNORECASE)
560 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000561 if not m:
562 return None
563 s = m.group(1)
564 try:
565 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000566 except (OverflowError, ValueError):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000567 return int(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000568
569
Guido van Rossum70297d32001-08-17 17:24:29 +0000570_227_re = None
571
Guido van Rossumd2560b01996-05-28 23:41:25 +0000572def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000573 '''Parse the '227' response for a PASV request.
574 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
575 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000576
Tim Peters88869f92001-01-14 23:36:06 +0000577 if resp[:3] != '227':
578 raise error_reply, resp
Guido van Rossum70297d32001-08-17 17:24:29 +0000579 global _227_re
580 if _227_re is None:
581 import re
582 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)')
583 m = _227_re.search(resp)
584 if not m:
Tim Peters88869f92001-01-14 23:36:06 +0000585 raise error_proto, resp
Guido van Rossum70297d32001-08-17 17:24:29 +0000586 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000587 host = '.'.join(numbers[:4])
588 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000589 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000590
591
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000592def parse229(resp, peer):
593 '''Parse the '229' response for a EPSV request.
594 Raises error_proto if it does not contain '(|||port|)'
595 Return ('host.addr.as.numbers', port#) tuple.'''
596
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000597 if resp[:3] != '229':
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000598 raise error_reply, resp
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000599 left = resp.find('(')
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000600 if left < 0: raise error_proto, resp
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000601 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000602 if right < 0:
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000603 raise error_proto, resp # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000604 if resp[left + 1] != resp[right - 1]:
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000605 raise error_proto, resp
Walter Dörwalda401ae42002-06-03 10:41:45 +0000606 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000607 if len(parts) != 5:
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000608 raise error_proto, resp
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000609 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000610 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000611 return host, port
612
613
Guido van Rossumc567c601992-11-05 22:22:37 +0000614def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000615 '''Parse the '257' response for a MKD or PWD request.
616 This is a response to a MKD or PWD request: a directory name.
617 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000618
Tim Peters88869f92001-01-14 23:36:06 +0000619 if resp[:3] != '257':
620 raise error_reply, resp
621 if resp[3:5] != ' "':
622 return '' # Not compliant to RFC 959, but UNIX ftpd does this
623 dirname = ''
624 i = 5
625 n = len(resp)
626 while i < n:
627 c = resp[i]
628 i = i+1
629 if c == '"':
630 if i >= n or resp[i] != '"':
631 break
632 i = i+1
633 dirname = dirname + c
634 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000635
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000636
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000637def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000638 '''Default retrlines callback to print a line.'''
639 print line
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000640
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000641
Guido van Rossumd2560b01996-05-28 23:41:25 +0000642def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000643 '''Copy file from one FTP-instance to another.'''
644 if not targetname: targetname = sourcename
645 type = 'TYPE ' + type
646 source.voidcmd(type)
647 target.voidcmd(type)
648 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
649 target.sendport(sourcehost, sourceport)
650 # RFC 959: the user must "listen" [...] BEFORE sending the
651 # transfer request.
652 # So: STOR before RETR, because here the target is a "user".
653 treply = target.sendcmd('STOR ' + targetname)
654 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
655 sreply = source.sendcmd('RETR ' + sourcename)
656 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
657 source.voidresp()
658 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000659
Tim Peters88869f92001-01-14 23:36:06 +0000660
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000661class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000662 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000663
Tim Peters88869f92001-01-14 23:36:06 +0000664 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000665
Tim Peters88869f92001-01-14 23:36:06 +0000666 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000667
Tim Peters88869f92001-01-14 23:36:06 +0000668 """
669 __defuser = None
670 __defpasswd = None
671 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000672
Tim Peters88869f92001-01-14 23:36:06 +0000673 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000674 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000675 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000676 filename = os.path.join(os.environ["HOME"],
677 ".netrc")
678 else:
679 raise IOError, \
680 "specify file to load or set $HOME"
681 self.__hosts = {}
682 self.__macros = {}
683 fp = open(filename, "r")
684 in_macro = 0
685 while 1:
686 line = fp.readline()
687 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000688 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000689 macro_lines.append(line)
690 continue
691 elif in_macro:
692 self.__macros[macro_name] = tuple(macro_lines)
693 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000694 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000695 host = user = passwd = acct = None
696 default = 0
697 i = 0
698 while i < len(words):
699 w1 = words[i]
700 if i+1 < len(words):
701 w2 = words[i + 1]
702 else:
703 w2 = None
704 if w1 == 'default':
705 default = 1
706 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000707 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000708 i = i + 1
709 elif w1 == 'login' and w2:
710 user = w2
711 i = i + 1
712 elif w1 == 'password' and w2:
713 passwd = w2
714 i = i + 1
715 elif w1 == 'account' and w2:
716 acct = w2
717 i = i + 1
718 elif w1 == 'macdef' and w2:
719 macro_name = w2
720 macro_lines = []
721 in_macro = 1
722 break
723 i = i + 1
724 if default:
725 self.__defuser = user or self.__defuser
726 self.__defpasswd = passwd or self.__defpasswd
727 self.__defacct = acct or self.__defacct
728 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000729 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000730 ouser, opasswd, oacct = \
731 self.__hosts[host]
732 user = user or ouser
733 passwd = passwd or opasswd
734 acct = acct or oacct
735 self.__hosts[host] = user, passwd, acct
736 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000737
Tim Peters88869f92001-01-14 23:36:06 +0000738 def get_hosts(self):
739 """Return a list of hosts mentioned in the .netrc file."""
740 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000741
Tim Peters88869f92001-01-14 23:36:06 +0000742 def get_account(self, host):
743 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000744
Tim Peters88869f92001-01-14 23:36:06 +0000745 The return value is a triple containing userid,
746 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000747
Tim Peters88869f92001-01-14 23:36:06 +0000748 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000749 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000750 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000751 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000752 user, passwd, acct = self.__hosts[host]
753 user = user or self.__defuser
754 passwd = passwd or self.__defpasswd
755 acct = acct or self.__defacct
756 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +0000757
Tim Peters88869f92001-01-14 23:36:06 +0000758 def get_macros(self):
759 """Return a list of all defined macro names."""
760 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000761
Tim Peters88869f92001-01-14 23:36:06 +0000762 def get_macro(self, macro):
763 """Return a sequence of lines which define a named macro."""
764 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000765
Fred Drake475d51d1997-06-24 22:02:54 +0000766
Tim Peters88869f92001-01-14 23:36:06 +0000767
Guido van Rossum1115ab21992-11-04 15:51:30 +0000768def test():
Tim Peters88869f92001-01-14 23:36:06 +0000769 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000770 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
771
772 -d dir
773 -l list
774 -p password
775 '''
776
777 if len(sys.argv) < 2:
778 print test.__doc__
779 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +0000780
Tim Peters88869f92001-01-14 23:36:06 +0000781 debugging = 0
782 rcfile = None
783 while sys.argv[1] == '-d':
784 debugging = debugging+1
785 del sys.argv[1]
786 if sys.argv[1][:2] == '-r':
787 # get name of alternate ~/.netrc file:
788 rcfile = sys.argv[1][2:]
789 del sys.argv[1]
790 host = sys.argv[1]
791 ftp = FTP(host)
792 ftp.set_debuglevel(debugging)
793 userid = passwd = acct = ''
794 try:
795 netrc = Netrc(rcfile)
796 except IOError:
797 if rcfile is not None:
798 sys.stderr.write("Could not open account file"
799 " -- using anonymous login.")
800 else:
801 try:
802 userid, passwd, acct = netrc.get_account(host)
803 except KeyError:
804 # no account for host
805 sys.stderr.write(
806 "No account -- using anonymous login.")
807 ftp.login(userid, passwd, acct)
808 for file in sys.argv[2:]:
809 if file[:2] == '-l':
810 ftp.dir(file[2:])
811 elif file[:2] == '-d':
812 cmd = 'CWD'
813 if file[2:]: cmd = cmd + ' ' + file[2:]
814 resp = ftp.sendcmd(cmd)
815 elif file == '-p':
816 ftp.set_pasv(not ftp.passiveserver)
817 else:
818 ftp.retrbinary('RETR ' + file, \
819 sys.stdout.write, 1024)
820 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +0000821
822
823if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +0000824 test()