Skip to content

Instantly share code, notes, and snippets.

@dcparker
Created March 25, 2009 18:47

Revisions

  1. dcparker revised this gist Jan 14, 2010. 1 changed file with 14 additions and 1 deletion.
    15 changes: 14 additions & 1 deletion ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -49,11 +49,24 @@ def connect(host, port=FTP_PORT)
    if @sock && !@sock.closed?
    voidcmd("ABOR") rescue EOFError
    voidcmd("QUIT") rescue EOFError
    @sock.close
    close
    end
    }
    end

    def abort
    voidcmd("ABOR") rescue EOFError
    end

    def quit
    voidcmd("QUIT") rescue EOFError
    end

    def close
    @sock.close # SSL
    @sock.io.close # TCP
    end

    def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
    synchronize do
    voidcmd("TYPE I")
  2. dcparker revised this gist Apr 5, 2009. 1 changed file with 57 additions and 3 deletions.
    60 changes: 57 additions & 3 deletions ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -2,12 +2,16 @@
    require 'openssl'
    require 'net/ftp'

    class Net::FTPS < Net::FTP
    end

    class Net::FTPS::Implicit < Net::FTP
    FTP_PORT = 990

    def initialize(host=nil, user=nil, passwd=nil, acct=nil)
    super
    @passive = true
    @binary = false
    @debug_mode = true
    @data_protection = 'P'
    @data_protected = false
    @@ -43,8 +47,8 @@ def connect(host, port=FTP_PORT)
    getresp
    at_exit {
    if @sock && !@sock.closed?
    voidcmd("ABOR")
    voidcmd("QUIT")
    voidcmd("ABOR") rescue EOFError
    voidcmd("QUIT") rescue EOFError
    @sock.close
    end
    }
    @@ -106,6 +110,56 @@ def retrlines(cmd) # :yield: line
    end
    end

    #
    # Puts the connection into binary (image) mode, issues the given server-side
    # command (such as "STOR myfile"), and sends the contents of the file named
    # +file+ to the server. If the optional block is given, it also passes it
    # the data, in chunks of +blocksize+ characters.
    #
    def storbinary(cmd, file, blocksize, rest_offset = nil, &block) # :yield: data
    if rest_offset
    file.seek(rest_offset, IO::SEEK_SET)
    end
    synchronize do
    voidcmd("TYPE I")
    conn = transfercmd(cmd, rest_offset)
    loop do
    buf = file.read(blocksize)
    break if buf == nil
    conn.write(buf)
    yield(buf) if block
    end
    conn.close # closes the SSL
    conn.io.close # closes the TCP below it
    voidresp
    end
    end

    #
    # Puts the connection into ASCII (text) mode, issues the given server-side
    # command (such as "STOR myfile"), and sends the contents of the file
    # named +file+ to the server, one line at a time. If the optional block is
    # given, it also passes it the lines.
    #
    def storlines(cmd, file, &block) # :yield: line
    synchronize do
    voidcmd("TYPE A")
    conn = transfercmd(cmd)
    loop do
    buf = file.gets
    break if buf == nil
    if buf[-2, 2] != CRLF
    buf = buf.chomp + CRLF
    end
    conn.write(buf)
    yield(buf) if block
    end
    conn.close # closes the SSL
    conn.io.close # closes the TCP below it
    voidresp
    end
    end

    def transfercmd(cmd, rest_offset=nil)
    unless @data_protected
    voidcmd('PBSZ 0')
    @@ -123,7 +177,7 @@ def transfercmd(cmd, rest_offset=nil)
    end
    putline(cmd)
    conn = open_socket(host, port, true)
    resp = getresp
    resp = getresp # Should be a 150 response
    if resp[0] != ?1
    raise FTPReplyError, resp
    end
  3. dcparker revised this gist Mar 25, 2009. 1 changed file with 5 additions and 3 deletions.
    8 changes: 5 additions & 3 deletions ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -42,9 +42,11 @@ def connect(host, port=FTP_PORT)
    mon_initialize
    getresp
    at_exit {
    voidcmd("ABOR")
    voidcmd("QUIT")
    @sock.close
    if @sock && !@sock.closed?
    voidcmd("ABOR")
    voidcmd("QUIT")
    @sock.close
    end
    }
    end

  4. dcparker revised this gist Mar 25, 2009. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    require 'openssl'
    require 'net/ftp'

    class Net::FtpsImplicit < Net::FTP
    class Net::FTPS::Implicit < Net::FTP
    FTP_PORT = 990

    def initialize(host=nil, user=nil, passwd=nil, acct=nil)
  5. dcparker revised this gist Mar 25, 2009. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,8 @@
    require 'socket'
    require 'openssl'
    require 'net/ftptls'
    require 'net/ftp'

    class FtpsImplicit < Net::FTP
    class Net::FtpsImplicit < Net::FTP
    FTP_PORT = 990

    def initialize(host=nil, user=nil, passwd=nil, acct=nil)
  6. dcparker revised this gist Mar 25, 2009. 1 changed file with 6 additions and 11 deletions.
    17 changes: 6 additions & 11 deletions ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    require 'socket'
    require 'openssl'
    require 'net/ftp'
    require 'net/ftptls'

    class FtpsImplicit < Net::FTP
    FTP_PORT = 990
    @@ -15,30 +15,24 @@ def initialize(host=nil, user=nil, passwd=nil, acct=nil)
    attr_accessor :data_protection

    def open_socket(host, port, data_socket=false)
    puts "Opening socket to #{host}, #{port}"
    # sleep 30 if data_socket
    tcpsock = if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
    @passive = true
    SOCKSsocket.open(host, port)
    else
    TCPSocket.new(host, port)
    end
    if !data_socket || @data_protection == 'P'
    # ssl_context.verify_mode = data_socket ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
    ssl_context = OpenSSL::SSL::SSLContext.new('SSLv23')
    ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
    ssl_context.key = nil
    ssl_context.cert = nil
    ssl_context.timeout = 10

    sock = OpenSSL::SSL::SSLSocket.new(tcpsock, ssl_context)
    puts "Connecting #{sock.inspect}..."
    sock.connect
    puts "Connected."
    else
    sock = tcpsock
    end
    # at_exit { sock.close; puts "ssl socket closed" }
    return sock
    end
    private :open_socket
    @@ -47,7 +41,11 @@ def connect(host, port=FTP_PORT)
    @sock = open_socket(host, port)
    mon_initialize
    getresp
    at_exit { puts "Quiting FTPS"; voidcmd("ABOR"); voidcmd("QUIT"); @sock.close }
    at_exit {
    voidcmd("ABOR")
    voidcmd("QUIT")
    @sock.close
    }
    end

    def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
    @@ -64,7 +62,6 @@ def get_data(sock,blocksize=1024)
    timeout = 10
    starttime = Time.now
    buffer = ''
    puts "Getting data from socket #{sock}"
    timeouts = 0
    catch :done do
    loop do
    @@ -82,7 +79,6 @@ def get_data(sock,blocksize=1024)
    lines = buffer.split(/\r?\n/)
    buffer = buffer =~ /\n$/ ? '' : lines.pop
    lines.each do |line|
    puts "Line: #{line}"
    yield(line)
    end
    end
    @@ -92,7 +88,6 @@ def get_data(sock,blocksize=1024)
    end
    end
    sock.close
    puts "Data: #{buffer}"
    buffer
    end

  7. dcparker created this gist Mar 25, 2009.
    151 changes: 151 additions & 0 deletions ftps_implicit.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,151 @@
    require 'socket'
    require 'openssl'
    require 'net/ftp'

    class FtpsImplicit < Net::FTP
    FTP_PORT = 990

    def initialize(host=nil, user=nil, passwd=nil, acct=nil)
    super
    @passive = true
    @debug_mode = true
    @data_protection = 'P'
    @data_protected = false
    end
    attr_accessor :data_protection

    def open_socket(host, port, data_socket=false)
    puts "Opening socket to #{host}, #{port}"
    # sleep 30 if data_socket
    tcpsock = if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
    @passive = true
    SOCKSsocket.open(host, port)
    else
    TCPSocket.new(host, port)
    end
    if !data_socket || @data_protection == 'P'
    # ssl_context.verify_mode = data_socket ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
    ssl_context = OpenSSL::SSL::SSLContext.new('SSLv23')
    ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
    ssl_context.key = nil
    ssl_context.cert = nil
    ssl_context.timeout = 10

    sock = OpenSSL::SSL::SSLSocket.new(tcpsock, ssl_context)
    puts "Connecting #{sock.inspect}..."
    sock.connect
    puts "Connected."
    else
    sock = tcpsock
    end
    # at_exit { sock.close; puts "ssl socket closed" }
    return sock
    end
    private :open_socket

    def connect(host, port=FTP_PORT)
    @sock = open_socket(host, port)
    mon_initialize
    getresp
    at_exit { puts "Quiting FTPS"; voidcmd("ABOR"); voidcmd("QUIT"); @sock.close }
    end

    def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
    synchronize do
    voidcmd("TYPE I")
    conn = transfercmd(cmd, rest_offset)
    data = get_data(conn,blocksize)
    yield(data)
    voidresp
    end
    end

    def get_data(sock,blocksize=1024)
    timeout = 10
    starttime = Time.now
    buffer = ''
    puts "Getting data from socket #{sock}"
    timeouts = 0
    catch :done do
    loop do
    event = select([sock],nil,nil,0.5)
    if event.nil? # nil would be a timeout, we'd do nothing and start loop over. Of course here we really have no timeout...
    timeouts += 0.5
    break if timeouts > timeout
    else
    event[0].each do |sock| # Iterate through all sockets that have pending activity
    if sock.eof? # Socket's been closed by the client
    throw :done
    else
    buffer << sock.readpartial(blocksize)
    if block_given? # we're in line-by-line mode
    lines = buffer.split(/\r?\n/)
    buffer = buffer =~ /\n$/ ? '' : lines.pop
    lines.each do |line|
    puts "Line: #{line}"
    yield(line)
    end
    end
    end
    end
    end
    end
    end
    sock.close
    puts "Data: #{buffer}"
    buffer
    end

    def retrlines(cmd) # :yield: line
    synchronize do
    voidcmd("TYPE A")
    voidcmd("STRU F")
    voidcmd("MODE S")
    conn = transfercmd(cmd)
    get_data(conn) do |line|
    yield(line)
    end
    getresp
    end
    end

    def transfercmd(cmd, rest_offset=nil)
    unless @data_protected
    voidcmd('PBSZ 0')
    sendcmd("PROT #{@data_protection}")
    @data_protected = true
    end

    if @passive
    host, port = makepasv
    if @resume and rest_offset
    resp = sendcmd("REST " + rest_offset.to_s)
    if resp[0] != ?3
    raise FTPReplyError, resp
    end
    end
    putline(cmd)
    conn = open_socket(host, port, true)
    resp = getresp
    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)
    if resp[0] != ?1
    raise FTPReplyError, resp
    end
    conn = sock.accept
    sock.close
    end
    return conn
    end
    private :transfercmd
    end