blob: a915b2d31ef3ffe585b08e9862aad45d31624674 [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.
Gregory P. Smithc64386b2008-01-22 00:19:41 +000035# Modified by Phil Schwartz to add storbinary and storlines callbacks.
Guido van Rossum98d9fd32000-02-28 15:12:25 +000036#
Guido van Rossumc567c601992-11-05 22:22:37 +000037
Guido van Rossum1115ab21992-11-04 15:51:30 +000038import os
39import sys
Guido van Rossum1115ab21992-11-04 15:51:30 +000040
Guido van Rossumb6775db1994-08-01 11:34:53 +000041# Import SOCKS module if it exists, else standard socket module socket
42try:
Tim Peters88869f92001-01-14 23:36:06 +000043 import SOCKS; socket = SOCKS; del SOCKS # import SOCKS as socket
44 from socket import getfqdn; socket.getfqdn = getfqdn; del getfqdn
Guido van Rossumb6775db1994-08-01 11:34:53 +000045except ImportError:
Tim Peters88869f92001-01-14 23:36:06 +000046 import socket
Guido van Rossumb6775db1994-08-01 11:34:53 +000047
Skip Montanaroeccd02a2001-01-20 23:34:12 +000048__all__ = ["FTP","Netrc"]
Guido van Rossum1115ab21992-11-04 15:51:30 +000049
Guido van Rossumd3166071993-05-24 14:16:22 +000050# Magic number from <socket.h>
Tim Peters88869f92001-01-14 23:36:06 +000051MSG_OOB = 0x1 # Process data out of band
Guido van Rossumd3166071993-05-24 14:16:22 +000052
53
Guido van Rossumc567c601992-11-05 22:22:37 +000054# The standard FTP server control port
Guido van Rossum1115ab21992-11-04 15:51:30 +000055FTP_PORT = 21
Guido van Rossum1115ab21992-11-04 15:51:30 +000056
57
Guido van Rossum21974791992-11-06 13:34:17 +000058# Exception raised when an error or invalid response is received
Fred Drake227b1202000-08-17 05:06:49 +000059class Error(Exception): pass
Tim Peters88869f92001-01-14 23:36:06 +000060class error_reply(Error): pass # unexpected [123]xx reply
61class error_temp(Error): pass # 4xx errors
62class error_perm(Error): pass # 5xx errors
63class error_proto(Error): pass # response does not begin with [1-5]
Guido van Rossum1115ab21992-11-04 15:51:30 +000064
65
Guido van Rossum21974791992-11-06 13:34:17 +000066# All exceptions (hopefully) that may be raised here and that aren't
67# (always) programming errors on our side
Gregory P. Smithe6c03032008-04-12 22:24:04 +000068all_errors = (Error, IOError, EOFError)
Guido van Rossum21974791992-11-06 13:34:17 +000069
70
Guido van Rossum1115ab21992-11-04 15:51:30 +000071# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
72CRLF = '\r\n'
73
74
Guido van Rossum1115ab21992-11-04 15:51:30 +000075# The class itself
76class FTP:
77
Tim Peters88869f92001-01-14 23:36:06 +000078 '''An FTP client class.
Guido van Rossumd2560b01996-05-28 23:41:25 +000079
Facundo Batista3f100992007-03-26 20:56:09 +000080 To create a connection, call the class using these arguments:
81 host, user, passwd, acct, timeout
82
83 The first four arguments are all strings, and have default value ''.
84 timeout must be numeric and defaults to None if not passed,
85 meaning that no timeout will be set on any ftp socket(s)
86 If a timeout is passed, then this is now the default timeout for all ftp
87 socket operations for this instance.
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000088
Tim Peters88869f92001-01-14 23:36:06 +000089 Then use self.connect() with optional host and port argument.
Guido van Rossumd2560b01996-05-28 23:41:25 +000090
Tim Peters88869f92001-01-14 23:36:06 +000091 To download a file, use ftp.retrlines('RETR ' + filename),
92 or ftp.retrbinary() with slightly different arguments.
93 To upload a file, use ftp.storlines() or ftp.storbinary(),
94 which have an open file as argument (see their definitions
95 below for details).
96 The download/upload functions first issue appropriate TYPE
97 and PORT or PASV commands.
Guido van Rossumd2560b01996-05-28 23:41:25 +000098'''
99
Fred Drake9c98a422001-02-28 21:46:37 +0000100 debugging = 0
101 host = ''
102 port = FTP_PORT
103 sock = None
104 file = None
105 welcome = None
106 passiveserver = 1
107
Tim Peters88869f92001-01-14 23:36:06 +0000108 # Initialization method (called by class instantiation).
109 # Initialize host to localhost, port to standard ftp port
110 # Optional arguments are host (for connect()),
111 # and user, passwd, acct (for login())
Facundo Batista3f100992007-03-26 20:56:09 +0000112 def __init__(self, host='', user='', passwd='', acct='', timeout=None):
113 self.timeout = timeout
Tim Peters88869f92001-01-14 23:36:06 +0000114 if host:
Fred Drake9c98a422001-02-28 21:46:37 +0000115 self.connect(host)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000116 if user:
Facundo Batista3f100992007-03-26 20:56:09 +0000117 self.login(user, passwd, acct)
Guido van Rossum52fc1f61993-06-17 12:38:10 +0000118
Facundo Batista93c33682007-03-30 13:00:35 +0000119 def connect(self, host='', port=0, timeout=None):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000120 '''Connect to host. Arguments are:
Facundo Batista3f100992007-03-26 20:56:09 +0000121 - host: hostname to connect to (string, default previous host)
122 - port: port to connect to (integer, default previous port)
123 '''
124 if host != '':
125 self.host = host
126 if port > 0:
127 self.port = port
Facundo Batista93c33682007-03-30 13:00:35 +0000128 if timeout is not None:
129 self.timeout = timeout
Facundo Batista3f100992007-03-26 20:56:09 +0000130 self.sock = socket.create_connection((self.host, self.port), self.timeout)
131 self.af = self.sock.family
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000132 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)
281 except socket.error, 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
Gregory P. Smith2230bcf2008-01-22 23:15:34 +0000316 argument to a REST command. This is essentially a server
Tim Peters88869f92001-01-14 23:36:06 +0000317 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()
Facundo Batista92493122007-06-06 15:13:37 +0000323 conn = socket.create_connection((host, port), self.timeout)
Tim Peters88869f92001-01-14 23:36:06 +0000324 if rest is not None:
325 self.sendcmd("REST %s" % rest)
326 resp = self.sendcmd(cmd)
Martin v. Löwis36cbc082006-11-12 18:48:13 +0000327 # Some servers apparently send a 200 reply to
328 # a LIST or STOR command, before the 150 reply
329 # (and way before the 226 reply). This seems to
330 # be in violation of the protocol (which only allows
331 # 1xx or error messages for LIST), so we just discard
332 # this response.
333 if resp[0] == '2':
Tim Petersf733abb2007-01-30 03:03:46 +0000334 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000335 if resp[0] != '1':
336 raise error_reply, resp
337 else:
338 sock = self.makeport()
339 if rest is not None:
340 self.sendcmd("REST %s" % rest)
341 resp = self.sendcmd(cmd)
Martin v. Löwis36cbc082006-11-12 18:48:13 +0000342 # See above.
343 if resp[0] == '2':
Tim Petersf733abb2007-01-30 03:03:46 +0000344 resp = self.getresp()
Tim Peters88869f92001-01-14 23:36:06 +0000345 if resp[0] != '1':
346 raise error_reply, resp
347 conn, sockaddr = sock.accept()
348 if resp[:3] == '150':
349 # this is conditional in case we received a 125
350 size = parse150(resp)
351 return conn, size
Fred Drake4de02d91997-01-10 18:26:09 +0000352
Tim Peters88869f92001-01-14 23:36:06 +0000353 def transfercmd(self, cmd, rest=None):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000354 """Like ntransfercmd() but returns only the socket."""
Tim Peters88869f92001-01-14 23:36:06 +0000355 return self.ntransfercmd(cmd, rest)[0]
Guido van Rossumc567c601992-11-05 22:22:37 +0000356
Tim Peters88869f92001-01-14 23:36:06 +0000357 def login(self, user = '', passwd = '', acct = ''):
358 '''Login, default anonymous.'''
359 if not user: user = 'anonymous'
360 if not passwd: passwd = ''
361 if not acct: acct = ''
362 if user == 'anonymous' and passwd in ('', '-'):
Tim Peterse4418602002-02-16 07:34:19 +0000363 # If there is no anonymous ftp password specified
364 # then we'll just use anonymous@
365 # We don't send any other thing because:
366 # - We want to remain anonymous
367 # - We want to stop SPAM
368 # - We don't want to let ftp sites to discriminate by the user,
369 # host or country.
Guido van Rossumc33e0772001-12-28 20:54:28 +0000370 passwd = passwd + 'anonymous@'
Tim Peters88869f92001-01-14 23:36:06 +0000371 resp = self.sendcmd('USER ' + user)
372 if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
373 if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
374 if resp[0] != '2':
375 raise error_reply, resp
376 return resp
Guido van Rossumc567c601992-11-05 22:22:37 +0000377
Tim Peters88869f92001-01-14 23:36:06 +0000378 def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000379 """Retrieve data in binary mode. A new port is created for you.
Barry Warsaw100d81e2000-09-01 06:09:23 +0000380
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000381 Args:
382 cmd: A RETR command.
383 callback: A single parameter callable to be called on each
384 block of data read.
385 blocksize: The maximum number of bytes to read from the
386 socket at one time. [default: 8192]
387 rest: Passed to transfercmd(). [default: None]
Guido van Rossum1115ab21992-11-04 15:51:30 +0000388
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000389 Returns:
390 The response code.
Tim Peters88869f92001-01-14 23:36:06 +0000391 """
392 self.voidcmd('TYPE I')
393 conn = self.transfercmd(cmd, rest)
394 while 1:
395 data = conn.recv(blocksize)
396 if not data:
397 break
398 callback(data)
399 conn.close()
400 return self.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000401
Tim Peters88869f92001-01-14 23:36:06 +0000402 def retrlines(self, cmd, callback = None):
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000403 """Retrieve data in line mode. A new port is created for you.
404
405 Args:
Gregory P. Smith2230bcf2008-01-22 23:15:34 +0000406 cmd: A RETR, LIST, NLST, or MLSD command.
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000407 callback: An optional single parameter callable that is called
408 for each line with the trailing CRLF stripped.
409 [default: print_line()]
410
411 Returns:
412 The response code.
413 """
Raymond Hettingere874fc32002-05-12 05:53:51 +0000414 if callback is None: callback = print_line
Tim Peters88869f92001-01-14 23:36:06 +0000415 resp = self.sendcmd('TYPE A')
416 conn = self.transfercmd(cmd)
417 fp = conn.makefile('rb')
418 while 1:
419 line = fp.readline()
Walter Dörwald70a6b492004-02-12 17:35:32 +0000420 if self.debugging > 2: print '*retr*', repr(line)
Tim Peters88869f92001-01-14 23:36:06 +0000421 if not line:
422 break
423 if line[-2:] == CRLF:
424 line = line[:-2]
425 elif line[-1:] == '\n':
426 line = line[:-1]
427 callback(line)
428 fp.close()
429 conn.close()
430 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000431
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000432 def storbinary(self, cmd, fp, blocksize=8192, callback=None):
433 """Store a file in binary mode. A new port is created for you.
434
435 Args:
436 cmd: A STOR command.
437 fp: A file-like object with a read(num_bytes) method.
438 blocksize: The maximum data size to read from fp and send over
439 the connection at once. [default: 8192]
440 callback: An optional single parameter callable that is called on
441 on each block of data after it is sent. [default: None]
442
443 Returns:
444 The response code.
445 """
Tim Peters88869f92001-01-14 23:36:06 +0000446 self.voidcmd('TYPE I')
447 conn = self.transfercmd(cmd)
448 while 1:
449 buf = fp.read(blocksize)
450 if not buf: break
Martin v. Löwise12454f2002-02-16 23:06:19 +0000451 conn.sendall(buf)
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000452 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000453 conn.close()
454 return self.voidresp()
Guido van Rossumc567c601992-11-05 22:22:37 +0000455
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000456 def storlines(self, cmd, fp, callback=None):
457 """Store a file in line mode. A new port is created for you.
458
459 Args:
460 cmd: A STOR command.
461 fp: A file-like object with a readline() method.
462 callback: An optional single parameter callable that is called on
463 on each line after it is sent. [default: None]
464
465 Returns:
466 The response code.
467 """
Tim Peters88869f92001-01-14 23:36:06 +0000468 self.voidcmd('TYPE A')
469 conn = self.transfercmd(cmd)
470 while 1:
471 buf = fp.readline()
472 if not buf: break
473 if buf[-2:] != CRLF:
474 if buf[-1] in CRLF: buf = buf[:-1]
475 buf = buf + CRLF
Martin v. Löwise12454f2002-02-16 23:06:19 +0000476 conn.sendall(buf)
Gregory P. Smithc64386b2008-01-22 00:19:41 +0000477 if callback: callback(buf)
Tim Peters88869f92001-01-14 23:36:06 +0000478 conn.close()
479 return self.voidresp()
Guido van Rossum0eaa74b1996-01-25 18:37:21 +0000480
Tim Peters88869f92001-01-14 23:36:06 +0000481 def acct(self, password):
482 '''Send new account name.'''
483 cmd = 'ACCT ' + password
484 return self.voidcmd(cmd)
Guido van Rossumc567c601992-11-05 22:22:37 +0000485
Tim Peters88869f92001-01-14 23:36:06 +0000486 def nlst(self, *args):
487 '''Return a list of files in a given directory (default the current).'''
488 cmd = 'NLST'
489 for arg in args:
490 cmd = cmd + (' ' + arg)
491 files = []
492 self.retrlines(cmd, files.append)
493 return files
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000494
Tim Peters88869f92001-01-14 23:36:06 +0000495 def dir(self, *args):
496 '''List a directory in long form.
497 By default list current directory to stdout.
498 Optional last argument is callback function; all
499 non-empty arguments before it are concatenated to the
500 LIST command. (This *should* only be used for a pathname.)'''
501 cmd = 'LIST'
502 func = None
503 if args[-1:] and type(args[-1]) != type(''):
504 args, func = args[:-1], args[-1]
505 for arg in args:
506 if arg:
507 cmd = cmd + (' ' + arg)
508 self.retrlines(cmd, func)
Guido van Rossumc567c601992-11-05 22:22:37 +0000509
Tim Peters88869f92001-01-14 23:36:06 +0000510 def rename(self, fromname, toname):
511 '''Rename a file.'''
512 resp = self.sendcmd('RNFR ' + fromname)
513 if resp[0] != '3':
514 raise error_reply, resp
515 return self.voidcmd('RNTO ' + toname)
Guido van Rossuma61bdeb1995-10-11 17:36:31 +0000516
Tim Peters88869f92001-01-14 23:36:06 +0000517 def delete(self, filename):
518 '''Delete a file.'''
519 resp = self.sendcmd('DELE ' + filename)
520 if resp[:3] in ('250', '200'):
521 return resp
522 elif resp[:1] == '5':
523 raise error_perm, resp
524 else:
525 raise error_reply, resp
Guido van Rossum02cf5821993-05-17 08:00:02 +0000526
Tim Peters88869f92001-01-14 23:36:06 +0000527 def cwd(self, dirname):
528 '''Change to a directory.'''
529 if dirname == '..':
530 try:
531 return self.voidcmd('CDUP')
532 except error_perm, msg:
Martin v. Löwisb5255112002-03-10 15:59:58 +0000533 if msg.args[0][:3] != '500':
534 raise
Tim Peters88869f92001-01-14 23:36:06 +0000535 elif dirname == '':
536 dirname = '.' # does nothing, but could return error
537 cmd = 'CWD ' + dirname
538 return self.voidcmd(cmd)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000539
Tim Peters88869f92001-01-14 23:36:06 +0000540 def size(self, filename):
541 '''Retrieve the size of a file.'''
Gregory P. Smith2230bcf2008-01-22 23:15:34 +0000542 # The SIZE command is defined in RFC-3659
Tim Peters88869f92001-01-14 23:36:06 +0000543 resp = self.sendcmd('SIZE ' + filename)
544 if resp[:3] == '213':
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000545 s = resp[3:].strip()
546 try:
547 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000548 except (OverflowError, ValueError):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000549 return long(s)
Guido van Rossumc567c601992-11-05 22:22:37 +0000550
Tim Peters88869f92001-01-14 23:36:06 +0000551 def mkd(self, dirname):
552 '''Make a directory, return its full pathname.'''
553 resp = self.sendcmd('MKD ' + dirname)
554 return parse257(resp)
Guido van Rossum98245091998-02-19 21:15:44 +0000555
Tim Peters88869f92001-01-14 23:36:06 +0000556 def rmd(self, dirname):
557 '''Remove a directory.'''
558 return self.voidcmd('RMD ' + dirname)
Guido van Rossum1115ab21992-11-04 15:51:30 +0000559
Tim Peters88869f92001-01-14 23:36:06 +0000560 def pwd(self):
561 '''Return current working directory.'''
562 resp = self.sendcmd('PWD')
563 return parse257(resp)
Guido van Rossum17ed1ae1993-06-01 13:21:04 +0000564
Tim Peters88869f92001-01-14 23:36:06 +0000565 def quit(self):
566 '''Quit, and close the connection.'''
567 resp = self.voidcmd('QUIT')
568 self.close()
569 return resp
570
571 def close(self):
572 '''Close the connection without assuming anything about it.'''
Fred Drake9c98a422001-02-28 21:46:37 +0000573 if self.file:
574 self.file.close()
575 self.sock.close()
576 self.file = self.sock = None
Guido van Rossumc567c601992-11-05 22:22:37 +0000577
578
Guido van Rossumacfb82a1997-10-22 20:49:52 +0000579_150_re = None
Fred Drake4de02d91997-01-10 18:26:09 +0000580
581def parse150(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000582 '''Parse the '150' response for a RETR request.
583 Returns the expected transfer size or None; size is not guaranteed to
584 be present in the 150 message.
585 '''
586 if resp[:3] != '150':
587 raise error_reply, resp
588 global _150_re
589 if _150_re is None:
590 import re
591 _150_re = re.compile("150 .* \((\d+) bytes\)", re.IGNORECASE)
592 m = _150_re.match(resp)
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000593 if not m:
594 return None
595 s = m.group(1)
596 try:
597 return int(s)
Guido van Rossum1f74cb32001-10-17 17:21:47 +0000598 except (OverflowError, ValueError):
Guido van Rossumb6aca6a2001-10-16 19:45:52 +0000599 return long(s)
Fred Drake4de02d91997-01-10 18:26:09 +0000600
601
Guido van Rossum70297d32001-08-17 17:24:29 +0000602_227_re = None
603
Guido van Rossumd2560b01996-05-28 23:41:25 +0000604def parse227(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000605 '''Parse the '227' response for a PASV request.
606 Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
607 Return ('host.addr.as.numbers', port#) tuple.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000608
Tim Peters88869f92001-01-14 23:36:06 +0000609 if resp[:3] != '227':
610 raise error_reply, resp
Guido van Rossum70297d32001-08-17 17:24:29 +0000611 global _227_re
612 if _227_re is None:
613 import re
614 _227_re = re.compile(r'(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)')
615 m = _227_re.search(resp)
616 if not m:
Tim Peters88869f92001-01-14 23:36:06 +0000617 raise error_proto, resp
Guido van Rossum70297d32001-08-17 17:24:29 +0000618 numbers = m.groups()
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000619 host = '.'.join(numbers[:4])
620 port = (int(numbers[4]) << 8) + int(numbers[5])
Tim Peters88869f92001-01-14 23:36:06 +0000621 return host, port
Guido van Rossumd2560b01996-05-28 23:41:25 +0000622
623
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000624def parse229(resp, peer):
625 '''Parse the '229' response for a EPSV request.
626 Raises error_proto if it does not contain '(|||port|)'
627 Return ('host.addr.as.numbers', port#) tuple.'''
628
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000629 if resp[:3] != '229':
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000630 raise error_reply, resp
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000631 left = resp.find('(')
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000632 if left < 0: raise error_proto, resp
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000633 right = resp.find(')', left + 1)
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000634 if right < 0:
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000635 raise error_proto, resp # should contain '(|||port|)'
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000636 if resp[left + 1] != resp[right - 1]:
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000637 raise error_proto, resp
Walter Dörwalda401ae42002-06-03 10:41:45 +0000638 parts = resp[left + 1:right].split(resp[left+1])
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000639 if len(parts) != 5:
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000640 raise error_proto, resp
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000641 host = peer[0]
Neal Norwitz7ce734c2002-05-31 14:13:04 +0000642 port = int(parts[3])
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000643 return host, port
644
645
Guido van Rossumc567c601992-11-05 22:22:37 +0000646def parse257(resp):
Tim Peters88869f92001-01-14 23:36:06 +0000647 '''Parse the '257' response for a MKD or PWD request.
648 This is a response to a MKD or PWD request: a directory name.
649 Returns the directoryname in the 257 reply.'''
Guido van Rossumd2560b01996-05-28 23:41:25 +0000650
Tim Peters88869f92001-01-14 23:36:06 +0000651 if resp[:3] != '257':
652 raise error_reply, resp
653 if resp[3:5] != ' "':
654 return '' # Not compliant to RFC 959, but UNIX ftpd does this
655 dirname = ''
656 i = 5
657 n = len(resp)
658 while i < n:
659 c = resp[i]
660 i = i+1
661 if c == '"':
662 if i >= n or resp[i] != '"':
663 break
664 i = i+1
665 dirname = dirname + c
666 return dirname
Guido van Rossum1115ab21992-11-04 15:51:30 +0000667
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000668
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000669def print_line(line):
Tim Peters88869f92001-01-14 23:36:06 +0000670 '''Default retrlines callback to print a line.'''
671 print line
Guido van Rossumae3b3a31993-11-30 13:43:54 +0000672
Guido van Rossum2f3941d1997-10-07 14:49:56 +0000673
Guido van Rossumd2560b01996-05-28 23:41:25 +0000674def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
Tim Peters88869f92001-01-14 23:36:06 +0000675 '''Copy file from one FTP-instance to another.'''
676 if not targetname: targetname = sourcename
677 type = 'TYPE ' + type
678 source.voidcmd(type)
679 target.voidcmd(type)
680 sourcehost, sourceport = parse227(source.sendcmd('PASV'))
681 target.sendport(sourcehost, sourceport)
682 # RFC 959: the user must "listen" [...] BEFORE sending the
683 # transfer request.
684 # So: STOR before RETR, because here the target is a "user".
685 treply = target.sendcmd('STOR ' + targetname)
686 if treply[:3] not in ('125', '150'): raise error_proto # RFC 959
687 sreply = source.sendcmd('RETR ' + sourcename)
688 if sreply[:3] not in ('125', '150'): raise error_proto # RFC 959
689 source.voidresp()
690 target.voidresp()
Guido van Rossum1115ab21992-11-04 15:51:30 +0000691
Tim Peters88869f92001-01-14 23:36:06 +0000692
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000693class Netrc:
Tim Peters88869f92001-01-14 23:36:06 +0000694 """Class to parse & provide access to 'netrc' format files.
Fred Drake475d51d1997-06-24 22:02:54 +0000695
Tim Peters88869f92001-01-14 23:36:06 +0000696 See the netrc(4) man page for information on the file format.
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000697
Tim Peters88869f92001-01-14 23:36:06 +0000698 WARNING: This class is obsolete -- use module netrc instead.
Guido van Rossumc822a451998-12-22 16:49:16 +0000699
Tim Peters88869f92001-01-14 23:36:06 +0000700 """
701 __defuser = None
702 __defpasswd = None
703 __defacct = None
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000704
Tim Peters88869f92001-01-14 23:36:06 +0000705 def __init__(self, filename=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +0000706 if filename is None:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000707 if "HOME" in os.environ:
Tim Peters88869f92001-01-14 23:36:06 +0000708 filename = os.path.join(os.environ["HOME"],
709 ".netrc")
710 else:
711 raise IOError, \
712 "specify file to load or set $HOME"
713 self.__hosts = {}
714 self.__macros = {}
715 fp = open(filename, "r")
716 in_macro = 0
717 while 1:
718 line = fp.readline()
719 if not line: break
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000720 if in_macro and line.strip():
Tim Peters88869f92001-01-14 23:36:06 +0000721 macro_lines.append(line)
722 continue
723 elif in_macro:
724 self.__macros[macro_name] = tuple(macro_lines)
725 in_macro = 0
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000726 words = line.split()
Tim Peters88869f92001-01-14 23:36:06 +0000727 host = user = passwd = acct = None
728 default = 0
729 i = 0
730 while i < len(words):
731 w1 = words[i]
732 if i+1 < len(words):
733 w2 = words[i + 1]
734 else:
735 w2 = None
736 if w1 == 'default':
737 default = 1
738 elif w1 == 'machine' and w2:
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000739 host = w2.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000740 i = i + 1
741 elif w1 == 'login' and w2:
742 user = w2
743 i = i + 1
744 elif w1 == 'password' and w2:
745 passwd = w2
746 i = i + 1
747 elif w1 == 'account' and w2:
748 acct = w2
749 i = i + 1
750 elif w1 == 'macdef' and w2:
751 macro_name = w2
752 macro_lines = []
753 in_macro = 1
754 break
755 i = i + 1
756 if default:
757 self.__defuser = user or self.__defuser
758 self.__defpasswd = passwd or self.__defpasswd
759 self.__defacct = acct or self.__defacct
760 if host:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000761 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000762 ouser, opasswd, oacct = \
763 self.__hosts[host]
764 user = user or ouser
765 passwd = passwd or opasswd
766 acct = acct or oacct
767 self.__hosts[host] = user, passwd, acct
768 fp.close()
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000769
Tim Peters88869f92001-01-14 23:36:06 +0000770 def get_hosts(self):
771 """Return a list of hosts mentioned in the .netrc file."""
772 return self.__hosts.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000773
Tim Peters88869f92001-01-14 23:36:06 +0000774 def get_account(self, host):
775 """Returns login information for the named host.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000776
Tim Peters88869f92001-01-14 23:36:06 +0000777 The return value is a triple containing userid,
778 password, and the accounting field.
Guido van Rossum8ca84201998-03-26 20:56:10 +0000779
Tim Peters88869f92001-01-14 23:36:06 +0000780 """
Eric S. Raymondc95bf692001-02-09 10:06:47 +0000781 host = host.lower()
Tim Peters88869f92001-01-14 23:36:06 +0000782 user = passwd = acct = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000783 if host in self.__hosts:
Tim Peters88869f92001-01-14 23:36:06 +0000784 user, passwd, acct = self.__hosts[host]
785 user = user or self.__defuser
786 passwd = passwd or self.__defpasswd
787 acct = acct or self.__defacct
788 return user, passwd, acct
Guido van Rossum8ca84201998-03-26 20:56:10 +0000789
Tim Peters88869f92001-01-14 23:36:06 +0000790 def get_macros(self):
791 """Return a list of all defined macro names."""
792 return self.__macros.keys()
Guido van Rossum8ca84201998-03-26 20:56:10 +0000793
Tim Peters88869f92001-01-14 23:36:06 +0000794 def get_macro(self, macro):
795 """Return a sequence of lines which define a named macro."""
796 return self.__macros[macro]
Guido van Rossum56d1e3a1997-03-14 04:16:54 +0000797
Fred Drake475d51d1997-06-24 22:02:54 +0000798
Tim Peters88869f92001-01-14 23:36:06 +0000799
Guido van Rossum1115ab21992-11-04 15:51:30 +0000800def test():
Tim Peters88869f92001-01-14 23:36:06 +0000801 '''Test program.
Raymond Hettingerc88a6c72005-04-05 04:31:09 +0000802 Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
803
804 -d dir
805 -l list
806 -p password
807 '''
808
809 if len(sys.argv) < 2:
810 print test.__doc__
811 sys.exit(0)
Guido van Rossumd2560b01996-05-28 23:41:25 +0000812
Tim Peters88869f92001-01-14 23:36:06 +0000813 debugging = 0
814 rcfile = None
815 while sys.argv[1] == '-d':
816 debugging = debugging+1
817 del sys.argv[1]
818 if sys.argv[1][:2] == '-r':
819 # get name of alternate ~/.netrc file:
820 rcfile = sys.argv[1][2:]
821 del sys.argv[1]
822 host = sys.argv[1]
823 ftp = FTP(host)
824 ftp.set_debuglevel(debugging)
825 userid = passwd = acct = ''
826 try:
827 netrc = Netrc(rcfile)
828 except IOError:
829 if rcfile is not None:
830 sys.stderr.write("Could not open account file"
831 " -- using anonymous login.")
832 else:
833 try:
834 userid, passwd, acct = netrc.get_account(host)
835 except KeyError:
836 # no account for host
837 sys.stderr.write(
838 "No account -- using anonymous login.")
839 ftp.login(userid, passwd, acct)
840 for file in sys.argv[2:]:
841 if file[:2] == '-l':
842 ftp.dir(file[2:])
843 elif file[:2] == '-d':
844 cmd = 'CWD'
845 if file[2:]: cmd = cmd + ' ' + file[2:]
846 resp = ftp.sendcmd(cmd)
847 elif file == '-p':
848 ftp.set_pasv(not ftp.passiveserver)
849 else:
850 ftp.retrbinary('RETR ' + file, \
851 sys.stdout.write, 1024)
852 ftp.quit()
Guido van Rossum221ec0b1995-08-04 04:39:30 +0000853
854
855if __name__ == '__main__':
Tim Peters88869f92001-01-14 23:36:06 +0000856 test()