171
183
private :with_binary
186
def return_code # :nodoc:
175
187
$stderr.puts("warning: Net::FTP#return_code is obsolete and do nothing")
192
def return_code=(s) # :nodoc:
181
193
$stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing")
184
def open_socket(host, port)
196
# Contructs a socket with +host+ and +port+.
198
# If SOCKSSocket is defined and the environment (ENV) defines
199
# SOCKS_SERVER, then a SOCKSSocket is returned, else a TCPSocket is
201
def open_socket(host, port) # :nodoc:
185
202
if defined? SOCKSSocket and ENV["SOCKS_SERVER"]
187
return SOCKSSocket.open(host, port)
204
return SOCKSSocket.open(host, port)
189
return TCPSocket.open(host, port)
206
return TCPSocket.open(host, port)
192
209
private :open_socket
200
217
def connect(host, port = FTP_PORT)
202
print "connect: ", host, ", ", port, "\n"
219
print "connect: ", host, ", ", port, "\n"
205
@sock = open_socket(host, port)
222
@sock = open_socket(host, port)
213
230
def set_socket(sock, get_greeting = true)
239
# If string +s+ includes the PASS command (password), then the contents of
240
# the password are cleaned from the string using "*"
241
def sanitize(s) # :nodoc:
223
242
if s =~ /^PASS /i
224
return s[0, 5] + "*" * (s.length - 5)
243
return s[0, 5] + "*" * (s.length - 5)
229
248
private :sanitize
250
# Ensures that +line+ has a control return / line feed (CRLF) and writes
252
def putline(line) # :nodoc:
233
print "put: ", sanitize(line), "\n"
254
print "put: ", sanitize(line), "\n"
235
256
line = line + CRLF
236
257
@sock.write(line)
261
# Reads a line from the sock. If EOF, then it will raise EOFError
262
def getline # :nodoc:
241
263
line = @sock.readline # if get EOF, raise EOFError
242
264
line.sub!(/(\r\n|\n|\r)\z/n, "")
244
print "get: ", sanitize(line), "\n"
266
print "get: ", sanitize(line), "\n"
272
# Receive a section of lines until the response code's match.
273
def getmultiline # :nodoc:
258
end until line[0, 3] == code and line[3] != ?-
281
end until line[0, 3] == code and line[3] != ?-
260
283
return buff << "\n"
262
285
private :getmultiline
287
# Recieves a response from the destination host.
289
# Returns the response code or raises FTPTempError, FTPPermError, or
291
def getresp # :nodoc:
265
292
@last_response = getmultiline
266
293
@last_response_code = @last_response[0, 3]
267
294
case @last_response_code
269
return @last_response
296
return @last_response
271
raise FTPTempError, @last_response
298
raise FTPTempError, @last_response
273
raise FTPPermError, @last_response
300
raise FTPPermError, @last_response
275
raise FTPProtoError, @last_response
302
raise FTPProtoError, @last_response
307
# Recieves a response.
309
# Raises FTPReplyError if the first position of the response code is not
311
def voidresp # :nodoc:
283
raise FTPReplyError, resp
314
raise FTPReplyError, resp
286
317
private :voidresp
308
def sendport(host, port)
339
# Constructs and send the appropriate PORT (or EPRT) command
340
def sendport(host, port) # :nodoc:
309
341
af = (@sock.peeraddr)[0]
310
342
if af == "AF_INET"
311
cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",")
343
cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",")
312
344
elsif af == "AF_INET6"
313
cmd = sprintf("EPRT |2|%s|%d|", host, port)
345
cmd = sprintf("EPRT |2|%s|%d|", host, port)
315
raise FTPProtoError, host
347
raise FTPProtoError, host
319
351
private :sendport
353
# Constructs a TCPServer socket, and sends it the PORT command
355
# Returns the constructed TCPServer socket
356
def makeport # :nodoc:
322
357
sock = TCPServer.open(@sock.addr[3], 0)
323
358
port = sock.addr[1]
324
359
host = sock.addr[3]
325
resp = sendport(host, port)
328
363
private :makeport
365
# sends the appropriate command to enable a passive connection
366
def makepasv # :nodoc:
331
367
if @sock.peeraddr[0] == "AF_INET"
332
host, port = parse227(sendcmd("PASV"))
368
host, port = parse227(sendcmd("PASV"))
334
host, port = parse229(sendcmd("EPSV"))
335
# host, port = parse228(sendcmd("LPSV"))
370
host, port = parse229(sendcmd("EPSV"))
371
# host, port = parse228(sendcmd("LPSV"))
337
373
return host, port
339
375
private :makepasv
341
def transfercmd(cmd, rest_offset = nil)
377
# Constructs a connection for transferring data
378
def transfercmd(cmd, rest_offset = nil) # :nodoc:
343
host, port = makepasv
344
conn = open_socket(host, port)
345
if @resume and rest_offset
346
resp = sendcmd("REST " + rest_offset.to_s)
348
raise FTPReplyError, resp
380
host, port = makepasv
381
conn = open_socket(host, port)
382
if @resume and rest_offset
383
resp = sendcmd("REST " + rest_offset.to_s)
385
raise FTPReplyError, resp
352
389
# skip 2XX for some ftp servers
353
390
resp = getresp if resp[0] == ?2
355
raise FTPReplyError, resp
392
raise FTPReplyError, resp
359
if @resume and rest_offset
360
resp = sendcmd("REST " + rest_offset.to_s)
362
raise FTPReplyError, resp
396
if @resume and rest_offset
397
resp = sendcmd("REST " + rest_offset.to_s)
399
raise FTPReplyError, resp
366
403
# skip 2XX for some ftp servers
367
404
resp = getresp if resp[0] == ?2
369
raise FTPReplyError, resp
406
raise FTPReplyError, resp
386
423
def login(user = "anonymous", passwd = nil, acct = nil)
387
424
if user == "anonymous" and passwd == nil
388
passwd = "anonymous@"
425
passwd = "anonymous@"
393
resp = sendcmd('USER ' + user)
430
resp = sendcmd('USER ' + user)
395
432
raise FTPReplyError, resp if passwd.nil?
396
resp = sendcmd('PASS ' + passwd)
433
resp = sendcmd('PASS ' + passwd)
399
436
raise FTPReplyError, resp if acct.nil?
400
resp = sendcmd('ACCT ' + acct)
437
resp = sendcmd('ACCT ' + acct)
404
raise FTPReplyError, resp
441
raise FTPReplyError, resp
407
444
send_type_command
538
f.binmode if localfile
539
retrbinary("RETR " + remotefile.to_s, blocksize, rest_offset) do |data|
540
f.write(data) if localfile
541
yield(data) if block_given?
575
f.binmode if localfile
576
retrbinary("RETR " + remotefile.to_s, blocksize, rest_offset) do |data|
577
f.write(data) if localfile
578
yield(data) if block_given?
542
579
result.concat(data) if result
579
616
# binary). See #gettextfile and #getbinaryfile.
581
618
def get(remotefile, localfile = File.basename(remotefile),
582
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
619
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
584
getbinaryfile(remotefile, localfile, blocksize, &block)
621
getbinaryfile(remotefile, localfile, blocksize, &block)
586
gettextfile(remotefile, localfile, &block)
623
gettextfile(remotefile, localfile, &block)
635
672
# (text or binary). See #puttextfile and #putbinaryfile.
637
674
def put(localfile, remotefile = File.basename(localfile),
638
blocksize = DEFAULT_BLOCKSIZE, &block)
675
blocksize = DEFAULT_BLOCKSIZE, &block)
640
putbinaryfile(localfile, remotefile, blocksize, &block)
677
putbinaryfile(localfile, remotefile, blocksize, &block)
642
puttextfile(localfile, remotefile, &block)
679
puttextfile(localfile, remotefile, &block)
647
# Sends the ACCT command. TODO: more info.
684
# Sends the ACCT command.
686
# This is a less common FTP command, to send account
687
# information if the destination host requires it.
649
689
def acct(account)
650
690
cmd = "ACCT " + account
873
915
@sock == nil or @sock.closed?
918
# handler for response code 227
919
# (Entering Passive Mode (h1,h2,h3,h4,p1,p2))
921
# Returns host and port.
922
def parse227(resp) # :nodoc:
877
923
if resp[0, 3] != "227"
878
raise FTPReplyError, resp
924
raise FTPReplyError, resp
880
926
left = resp.index("(")
881
927
right = resp.index(")")
882
928
if left == nil or right == nil
883
raise FTPProtoError, resp
929
raise FTPProtoError, resp
885
931
numbers = resp[left + 1 .. right - 1].split(",")
886
932
if numbers.length != 6
887
raise FTPProtoError, resp
933
raise FTPProtoError, resp
889
935
host = numbers[0, 4].join(".")
890
936
port = (numbers[4].to_i << 8) + numbers[5].to_i
893
939
private :parse227
941
# handler for response code 228
942
# (Entering Long Passive Mode)
944
# Returns host and port.
945
def parse228(resp) # :nodoc:
896
946
if resp[0, 3] != "228"
897
raise FTPReplyError, resp
947
raise FTPReplyError, resp
899
949
left = resp.index("(")
900
950
right = resp.index(")")
901
951
if left == nil or right == nil
902
raise FTPProtoError, resp
952
raise FTPProtoError, resp
904
954
numbers = resp[left + 1 .. right - 1].split(",")
905
955
if numbers[0] == "4"
906
if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
907
raise FTPProtoError, resp
909
host = numbers[2, 4].join(".")
910
port = (numbers[7].to_i << 8) + numbers[8].to_i
956
if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
957
raise FTPProtoError, resp
959
host = numbers[2, 4].join(".")
960
port = (numbers[7].to_i << 8) + numbers[8].to_i
911
961
elsif numbers[0] == "6"
912
if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
913
raise FTPProtoError, resp
915
v6 = ["", "", "", "", "", "", "", ""]
917
v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
918
numbers[(i * 2) + 3].to_i)
920
host = v6[0, 8].join(":")
921
port = (numbers[19].to_i << 8) + numbers[20].to_i
962
if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
963
raise FTPProtoError, resp
965
v6 = ["", "", "", "", "", "", "", ""]
967
v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
968
numbers[(i * 2) + 3].to_i)
970
host = v6[0, 8].join(":")
971
port = (numbers[19].to_i << 8) + numbers[20].to_i
923
973
return host, port
925
975
private :parse228
977
# handler for response code 229
978
# (Extended Passive Mode Entered)
980
# Returns host and port.
981
def parse229(resp) # :nodoc:
928
982
if resp[0, 3] != "229"
929
raise FTPReplyError, resp
983
raise FTPReplyError, resp
931
985
left = resp.index("(")
932
986
right = resp.index(")")
933
987
if left == nil or right == nil
934
raise FTPProtoError, resp
988
raise FTPProtoError, resp
936
990
numbers = resp[left + 1 .. right - 1].split(resp[left + 1, 1])
937
991
if numbers.length != 4
938
raise FTPProtoError, resp
992
raise FTPProtoError, resp
940
994
port = numbers[3].to_i
941
995
host = (@sock.peeraddr())[3]