Project

General

Profile

Bug #4710 » ruby_doc_updates-20110516_vbatts.patch

vbatts (Vincent Batts), 05/16/2011 10:17 PM

View differences:

lib/net/ftp.rb
@sock = NullSocket.new
@logged_in = false
if host
connect(host)
if user
login(user, passwd, acct)
end
connect(host)
if user
login(user, passwd, acct)
end
end
end
# A setter to toggle transfers in binary mode.
# +newmode+ is either +true+ or +false+
def binary=(newmode)
if newmode != @binary
@binary = newmode
......
end
end
# Sends a command to destination host, with the current binary sendmode type.
# If binary mode is +true+, then send "TYPE I" (image)
# else send "TYPE A" (ascii).
def send_type_command
if @binary
voidcmd("TYPE I")
......
end
private :send_type_command
# Toggles transfers in binary mode and yields to a block.
# This preserves your current binary send mode, but allows a temporary
# transaction with binary sendmode of +newmode+.
#
# +newmode+ is either +true+ or +false+
def with_binary(newmode)
oldmode = binary
self.binary = newmode
......
$stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing")
end
# Contructs a socket with +host+ and +port+.
# If SOCKSSocket is defined and the environment (ENV)
# defines SOCKS_SERVER, then a SOCKSSocket is returned,
# else a TCPSocket is returned.
def open_socket(host, port)
if defined? SOCKSSocket and ENV["SOCKS_SERVER"]
@passive = true
return SOCKSSocket.open(host, port)
@passive = true
return SOCKSSocket.open(host, port)
else
return TCPSocket.open(host, port)
return TCPSocket.open(host, port)
end
end
private :open_socket
......
#
def connect(host, port = FTP_PORT)
if @debug_mode
print "connect: ", host, ", ", port, "\n"
print "connect: ", host, ", ", port, "\n"
end
synchronize do
@sock = open_socket(host, port)
voidresp
@sock = open_socket(host, port)
voidresp
end
end
......
#
def set_socket(sock, get_greeting = true)
synchronize do
@sock = sock
if get_greeting
voidresp
end
@sock = sock
if get_greeting
voidresp
end
end
end
# If string +s+ includes the PASS command (password),
# then the contents of the password are cleaned from the string using "*"
def sanitize(s)
if s =~ /^PASS /i
return s[0, 5] + "*" * (s.length - 5)
return s[0, 5] + "*" * (s.length - 5)
else
return s
return s
end
end
private :sanitize
# Ensures that +line+ has a control return / line feed (CRLF)
# and writes it to the socket.
def putline(line)
if @debug_mode
print "put: ", sanitize(line), "\n"
print "put: ", sanitize(line), "\n"
end
line = line + CRLF
@sock.write(line)
end
private :putline
# Reads a line from the sock.
# If EOF, then it will raise EOFError
def getline
line = @sock.readline # if get EOF, raise EOFError
line.sub!(/(\r\n|\n|\r)\z/n, "")
if @debug_mode
print "get: ", sanitize(line), "\n"
print "get: ", sanitize(line), "\n"
end
return line
end
private :getline
# Receive a section of lines until the response code's match.
def getmultiline
line = getline
buff = line
if line[3] == ?-
code = line[0, 3]
begin
line = getline
buff << "\n" << line
end until line[0, 3] == code and line[3] != ?-
code = line[0, 3]
begin
line = getline
buff << "\n" << line
end until line[0, 3] == code and line[3] != ?-
end
return buff << "\n"
end
private :getmultiline
# Recieves a response from the destination host.
# Either returns the response code, FTPTempError,
# FTPPermError, or FTPProtoError
def getresp
@last_response = getmultiline
@last_response_code = @last_response[0, 3]
case @last_response_code
when /\A[123]/
return @last_response
return @last_response
when /\A4/
raise FTPTempError, @last_response
raise FTPTempError, @last_response
when /\A5/
raise FTPPermError, @last_response
raise FTPPermError, @last_response
else
raise FTPProtoError, @last_response
raise FTPProtoError, @last_response
end
end
private :getresp
# Recieves a response.
# Raises FTPReplyError if the first position of the response code is not equal 2.
def voidresp
resp = getresp
if resp[0] != ?2
raise FTPReplyError, resp
raise FTPReplyError, resp
end
end
private :voidresp
......
#
def sendcmd(cmd)
synchronize do
putline(cmd)
return getresp
putline(cmd)
return getresp
end
end
......
#
def voidcmd(cmd)
synchronize do
putline(cmd)
voidresp
putline(cmd)
voidresp
end
end
# Constructs and send the appropriate PORT (or EPRT) command
def sendport(host, port)
af = (@sock.peeraddr)[0]
if af == "AF_INET"
cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",")
cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",")
elsif af == "AF_INET6"
cmd = sprintf("EPRT |2|%s|%d|", host, port)
cmd = sprintf("EPRT |2|%s|%d|", host, port)
else
raise FTPProtoError, host
raise FTPProtoError, host
end
voidcmd(cmd)
end
private :sendport
# Constructs a TCPServer socket, and sends it the PORT command
#
# Returns the constructed TCPServer socket
def makeport
sock = TCPServer.open(@sock.addr[3], 0)
port = sock.addr[1]
......
end
private :makeport
# sends the appropriate command to enable a passive connection
def makepasv
if @sock.peeraddr[0] == "AF_INET"
host, port = parse227(sendcmd("PASV"))
host, port = parse227(sendcmd("PASV"))
else
host, port = parse229(sendcmd("EPSV"))
# host, port = parse228(sendcmd("LPSV"))
host, port = parse229(sendcmd("EPSV"))
# host, port = parse228(sendcmd("LPSV"))
end
return host, port
end
private :makepasv
# Constructs a connection for transferring data
def transfercmd(cmd, rest_offset = nil)
if @passive
host, port = makepasv
conn = open_socket(host, port)
if @resume and rest_offset
resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
raise FTPReplyError, resp
end
end
resp = sendcmd(cmd)
host, port = makepasv
conn = open_socket(host, port)
if @resume and rest_offset
resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
raise FTPReplyError, resp
end
end
resp = sendcmd(cmd)
# skip 2XX for some ftp servers
resp = getresp if resp[0] == ?2
if resp[0] != ?1
raise FTPReplyError, resp
end
if resp[0] != ?1
raise FTPReplyError, resp
end
else
sock = makeport
if @resume and rest_offset
resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
raise FTPReplyError, resp
end
end
resp = sendcmd(cmd)
sock = makeport
if @resume and rest_offset
resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
raise FTPReplyError, resp
end
end
resp = sendcmd(cmd)
# skip 2XX for some ftp servers
resp = getresp if resp[0] == ?2
if resp[0] != ?1
raise FTPReplyError, resp
end
conn = sock.accept
sock.close
if resp[0] != ?1
raise FTPReplyError, resp
end
conn = sock.accept
sock.close
end
return conn
end
......
#
def login(user = "anonymous", passwd = nil, acct = nil)
if user == "anonymous" and passwd == nil
passwd = "anonymous@"
passwd = "anonymous@"
end
resp = ""
synchronize do
resp = sendcmd('USER ' + user)
if resp[0] == ?3
resp = sendcmd('USER ' + user)
if resp[0] == ?3
raise FTPReplyError, resp if passwd.nil?
resp = sendcmd('PASS ' + passwd)
end
if resp[0] == ?3
resp = sendcmd('PASS ' + passwd)
end
if resp[0] == ?3
raise FTPReplyError, resp if acct.nil?
resp = sendcmd('ACCT ' + acct)
end
resp = sendcmd('ACCT ' + acct)
end
end
if resp[0] != ?2
raise FTPReplyError, resp
raise FTPReplyError, resp
end
@welcome = resp
send_type_command
......
#
def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
synchronize do
with_binary(true) do
with_binary(true) do
conn = transfercmd(cmd, rest_offset)
loop do
data = conn.read(blocksize)
......
#
def retrlines(cmd) # :yield: line
synchronize do
with_binary(false) do
with_binary(false) do
conn = transfercmd(cmd)
loop do
line = conn.gets
......
file.seek(rest_offset, IO::SEEK_SET)
end
synchronize do
with_binary(true) do
with_binary(true) do
conn = transfercmd(cmd)
loop do
buf = file.read(blocksize)
......
#
def storlines(cmd, file, &block) # :yield: line
synchronize do
with_binary(false) do
with_binary(false) do
conn = transfercmd(cmd)
loop do
buf = file.gets
......
# chunks.
#
def getbinaryfile(remotefile, localfile = File.basename(remotefile),
blocksize = DEFAULT_BLOCKSIZE) # :yield: data
blocksize = DEFAULT_BLOCKSIZE) # :yield: data
result = nil
if localfile
if @resume
......
result = ""
end
begin
f.binmode if localfile
retrbinary("RETR " + remotefile.to_s, blocksize, rest_offset) do |data|
f.write(data) if localfile
yield(data) if block_given?
f.binmode if localfile
retrbinary("RETR " + remotefile.to_s, blocksize, rest_offset) do |data|
f.write(data) if localfile
yield(data) if block_given?
result.concat(data) if result
end
end
return result
ensure
f.close if localfile
f.close if localfile
end
end
......
result = ""
end
begin
retrlines("RETR " + remotefile) do |line, newline|
retrlines("RETR " + remotefile) do |line, newline|
l = newline ? line + "\n" : line
f.print(l) if localfile
yield(line, newline) if block_given?
f.print(l) if localfile
yield(line, newline) if block_given?
result.concat(l) if result
end
end
return result
ensure
f.close if localfile
f.close if localfile
end
end
......
# binary). See #gettextfile and #getbinaryfile.
#
def get(remotefile, localfile = File.basename(remotefile),
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
if @binary
getbinaryfile(remotefile, localfile, blocksize, &block)
getbinaryfile(remotefile, localfile, blocksize, &block)
else
gettextfile(remotefile, localfile, &block)
gettextfile(remotefile, localfile, &block)
end
end
......
# data in +blocksize+ chunks.
#
def putbinaryfile(localfile, remotefile = File.basename(localfile),
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
if @resume
begin
rest_offset = size(remotefile)
......
rest_offset = nil
end
else
rest_offset = nil
rest_offset = nil
end
f = open(localfile)
begin
f.binmode
f.binmode
if rest_offset
storbinary("APPE " + remotefile, f, blocksize, rest_offset, &block)
else
storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
end
ensure
f.close
f.close
end
end
......
def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line
f = open(localfile)
begin
storlines("STOR " + remotefile, f, &block)
storlines("STOR " + remotefile, f, &block)
ensure
f.close
f.close
end
end
......
# (text or binary). See #puttextfile and #putbinaryfile.
#
def put(localfile, remotefile = File.basename(localfile),
blocksize = DEFAULT_BLOCKSIZE, &block)
blocksize = DEFAULT_BLOCKSIZE, &block)
if @binary
putbinaryfile(localfile, remotefile, blocksize, &block)
putbinaryfile(localfile, remotefile, blocksize, &block)
else
puttextfile(localfile, remotefile, &block)
puttextfile(localfile, remotefile, &block)
end
end
#
# Sends the ACCT command. TODO: more info.
# Sends the ACCT command.
#
# This is a less common FTP command, to send account
# information if the destination host requires it.
#
def acct(account)
cmd = "ACCT " + account
......
def nlst(dir = nil)
cmd = "NLST"
if dir
cmd = cmd + " " + dir
cmd = cmd + " " + dir
end
files = []
retrlines(cmd) do |line|
files.push(line)
files.push(line)
end
return files
end
......
def list(*args, &block) # :yield: line
cmd = "LIST"
args.each do |arg|
cmd = cmd + " " + arg.to_s
cmd = cmd + " " + arg.to_s
end
if block
retrlines(cmd, &block)
retrlines(cmd, &block)
else
lines = []
retrlines(cmd) do |line|
lines << line
end
return lines
lines = []
retrlines(cmd) do |line|
lines << line
end
return lines
end
end
alias ls list
......
def rename(fromname, toname)
resp = sendcmd("RNFR " + fromname)
if resp[0] != ?3
raise FTPReplyError, resp
raise FTPReplyError, resp
end
voidcmd("RNTO " + toname)
end
......
def delete(filename)
resp = sendcmd("DELE " + filename)
if resp[0, 3] == "250"
return
return
elsif resp[0] == ?5
raise FTPPermError, resp
raise FTPPermError, resp
else
raise FTPReplyError, resp
raise FTPReplyError, resp
end
end
......
#
def chdir(dirname)
if dirname == ".."
begin
voidcmd("CDUP")
return
rescue FTPPermError => e
if e.message[0, 3] != "500"
raise e
end
end
begin
voidcmd("CDUP")
return
rescue FTPPermError => e
if e.message[0, 3] != "500"
raise e
end
end
end
cmd = "CWD " + dirname
voidcmd(cmd)
......
def system
resp = sendcmd("SYST")
if resp[0, 3] != "215"
raise FTPReplyError, resp
raise FTPReplyError, resp
end
return resp[4 .. -1]
end
......
@sock.send(line, Socket::MSG_OOB)
resp = getmultiline
unless ["426", "226", "225"].include?(resp[0, 3])
raise FTPProtoError, resp
raise FTPProtoError, resp
end
return resp
end
......
def mdtm(filename)
resp = sendcmd("MDTM " + filename)
if resp[0, 3] == "213"
return resp[3 .. -1].strip
return resp[3 .. -1].strip
end
end
......
def help(arg = nil)
cmd = "HELP"
if arg
cmd = cmd + " " + arg
cmd = cmd + " " + arg
end
sendcmd(cmd)
end
......
#
# Issues a NOOP command.
#
# Does nothing except return a response.
#
def noop
voidcmd("NOOP")
......
@sock == nil or @sock.closed?
end
# handler for response code 227
# (Entering Passive Mode (h1,h2,h3,h4,p1,p2))
#
# Returns host and port.
def parse227(resp)
if resp[0, 3] != "227"
raise FTPReplyError, resp
raise FTPReplyError, resp
end
left = resp.index("(")
right = resp.index(")")
if left == nil or right == nil
raise FTPProtoError, resp
raise FTPProtoError, resp
end
numbers = resp[left + 1 .. right - 1].split(",")
if numbers.length != 6
raise FTPProtoError, resp
raise FTPProtoError, resp
end
host = numbers[0, 4].join(".")
port = (numbers[4].to_i << 8) + numbers[5].to_i
......
end
private :parse227
# handler for response code 228
# (Entering Long Passive Mode)
#
# Returns host and port.
def parse228(resp)
if resp[0, 3] != "228"
raise FTPReplyError, resp
raise FTPReplyError, resp
end
left = resp.index("(")
right = resp.index(")")
if left == nil or right == nil
raise FTPProtoError, resp
raise FTPProtoError, resp
end
numbers = resp[left + 1 .. right - 1].split(",")
if numbers[0] == "4"
if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
raise FTPProtoError, resp
end
host = numbers[2, 4].join(".")
port = (numbers[7].to_i << 8) + numbers[8].to_i
if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
raise FTPProtoError, resp
end
host = numbers[2, 4].join(".")
port = (numbers[7].to_i << 8) + numbers[8].to_i
elsif numbers[0] == "6"
if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
raise FTPProtoError, resp
end
v6 = ["", "", "", "", "", "", "", ""]
for i in 0 .. 7
v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
numbers[(i * 2) + 3].to_i)
end
host = v6[0, 8].join(":")
port = (numbers[19].to_i << 8) + numbers[20].to_i
if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
raise FTPProtoError, resp
end
v6 = ["", "", "", "", "", "", "", ""]
for i in 0 .. 7
v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
numbers[(i * 2) + 3].to_i)
end
host = v6[0, 8].join(":")
port = (numbers[19].to_i << 8) + numbers[20].to_i
end
return host, port
end
private :parse228
# handler for response code 229
# (Extended Passive Mode Entered)
#
# Returns host and port.
def parse229(resp)
if resp[0, 3] != "229"
raise FTPReplyError, resp
raise FTPReplyError, resp
end
left = resp.index("(")
right = resp.index(")")
if left == nil or right == nil
raise FTPProtoError, resp
raise FTPProtoError, resp
end
numbers = resp[left + 1 .. right - 1].split(resp[left + 1, 1])
if numbers.length != 4
raise FTPProtoError, resp
raise FTPProtoError, resp
end
port = numbers[3].to_i
host = (@sock.peeraddr())[3]
......
end
private :parse229
# handler for response code 257
# ("PATHNAME" created)
#
# Returns host and port.
def parse257(resp)
if resp[0, 3] != "257"
raise FTPReplyError, resp
raise FTPReplyError, resp
end
if resp[3, 2] != ' "'
return ""
return ""
end
dirname = ""
i = 5
n = resp.length
while i < n
c = resp[i, 1]
i = i + 1
if c == '"'
if i > n or resp[i, 1] != '"'
break
end
i = i + 1
end
dirname = dirname + c
c = resp[i, 1]
i = i + 1
if c == '"'
if i > n or resp[i, 1] != '"'
break
end
i = i + 1
end
dirname = dirname + c
end
return dirname
end
(1-1/2)