Class Net::FTP
In: lib/net/ftp.rb
Parent: Object

This class implements the File Transfer Protocol. If you have used a command-line FTP program, and are familiar with the commands, you will be able to use this class easily. Some extra features are included to take advantage of Ruby‘s style and strengths.

Example

  require 'net/ftp'

Example 1

  ftp = Net::FTP.new('ftp.netlab.co.jp')
  ftp.login
  files = ftp.chdir('pub/lang/ruby/contrib')
  files = ftp.list('n*')
  ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
  ftp.close

Example 2

  Net::FTP.open('ftp.netlab.co.jp') do |ftp|
    ftp.login
    files = ftp.chdir('pub/lang/ruby/contrib')
    files = ftp.list('n*')
    ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
  end

Major Methods

The following are the methods most likely to be useful to users:

Methods

abort   acct   chdir   close   closed?   connect   delete   dir   get   getaddress   getbinaryfile   getdir   getline   getmultiline   getresp   gettextfile   help   list   login   ls   makepasv   makeport   mdtm   mkdir   mtime   new   nlst   noop   open   open_socket   parse227   parse228   parse229   parse257   put   putbinaryfile   putline   puttextfile   pwd   quit   rename   retrbinary   retrlines   return_code   return_code=   rmdir   sanitize   sendcmd   sendport   set_socket   site   size   status   storbinary   storlines   system   transfercmd   voidcmd   voidresp  

Included Modules

MonitorMixin

External Aliases

last_response_code -> lastresp

Attributes

binary  [RW]  When true, transfers are performed in binary mode. Default: true.
debug_mode  [RW]  When true, all traffic to and from the server is written to +$stdout+. Default: false.
last_response  [R]  The server‘s last response.
last_response_code  [R]  The server‘s last response code.
passive  [RW]  When true, the connection is in passive mode. Default: false.
resume  [RW]  Sets or retrieves the resume status, which decides whether incomplete transfers are resumed or restarted. Default: false.
welcome  [R]  The server‘s welcome message.

Public Class methods

Creates and returns a new FTP object. If a host is given, a connection is made. Additionally, if the user is given, the given user name, password, and (optionally) account are used to log in. See login.

[Source]

     # File lib/net/ftp.rb, line 129
129:     def initialize(host = nil, user = nil, passwd = nil, acct = nil)
130:       super()
131:       @binary = true
132:       @passive = false
133:       @debug_mode = false
134:       @resume = false
135:       if host
136:         connect(host)
137:         if user
138:           login(user, passwd, acct)
139:         end
140:       end
141:     end

A synonym for FTP.new, but with a mandatory host parameter.

If a block is given, it is passed the FTP object, which will be closed when the block finishes, or when an exception is raised.

[Source]

     # File lib/net/ftp.rb, line 111
111:     def FTP.open(host, user = nil, passwd = nil, acct = nil)
112:       if block_given?
113:         ftp = new(host, user, passwd, acct)
114:         begin
115:           yield ftp
116:         ensure
117:           ftp.close
118:         end
119:       else
120:         new(host, user, passwd, acct)
121:       end
122:     end

Public Instance methods

Aborts the previous command (ABOR command).

[Source]

     # File lib/net/ftp.rb, line 743
743:     def abort
744:       line = "ABOR" + CRLF
745:       print "put: ABOR\n" if @debug_mode
746:       @sock.send(line, Socket::MSG_OOB)
747:       resp = getmultiline
748:       unless ["426", "226", "225"].include?(resp[0, 3])
749:         raise FTPProtoError, resp
750:       end
751:       return resp
752:     end

Sends the ACCT command. TODO: more info.

[Source]

     # File lib/net/ftp.rb, line 596
596:     def acct(account)
597:       cmd = "ACCT " + account
598:       voidcmd(cmd)
599:     end

Changes the (remote) directory.

[Source]

     # File lib/net/ftp.rb, line 666
666:     def chdir(dirname)
667:       if dirname == ".."
668:         begin
669:           voidcmd("CDUP")
670:           return
671:         rescue FTPPermError
672:           if $![0, 3] != "500"
673:             raise FTPPermError, $!
674:           end
675:         end
676:       end
677:       cmd = "CWD " + dirname
678:       voidcmd(cmd)
679:     end

Closes the connection. Further operations are impossible until you open a new connection with connect.

[Source]

     # File lib/net/ftp.rb, line 811
811:     def close
812:       @sock.close if @sock and not @sock.closed?
813:     end

Returns true iff the connection is closed.

[Source]

     # File lib/net/ftp.rb, line 818
818:     def closed?
819:       @sock == nil or @sock.closed?
820:     end

Establishes an FTP connection to host, optionally overriding the default port. If the environment variable SOCKS_SERVER is set, sets up the connection through a SOCKS proxy. Raises an exception (typically Errno::ECONNREFUSED) if the connection cannot be established.

[Source]

     # File lib/net/ftp.rb, line 170
170:     def connect(host, port = FTP_PORT)
171:       if @debug_mode
172:         print "connect: ", host, ", ", port, "\n"
173:       end
174:       synchronize do
175:         @sock = open_socket(host, port)
176:         voidresp
177:       end
178:     end

Deletes a file on the server.

[Source]

     # File lib/net/ftp.rb, line 652
652:     def delete(filename)
653:       resp = sendcmd("DELE " + filename)
654:       if resp[0, 3] == "250"
655:         return
656:       elsif resp[0] == ?5
657:         raise FTPPermError, resp
658:       else
659:         raise FTPReplyError, resp
660:       end
661:     end
dir(*args)

Alias for list

Retrieves remotefile in whatever mode the session is set (text or binary). See gettextfile and getbinaryfile.

[Source]

     # File lib/net/ftp.rb, line 532
532:     def get(remotefile, localfile = File.basename(remotefile),
533:             blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
534:       unless @binary
535:         gettextfile(remotefile, localfile, &block)
536:       else
537:         getbinaryfile(remotefile, localfile, blocksize, &block)
538:       end
539:     end

Retrieves remotefile in binary mode, storing the result in localfile. If a block is supplied, it is passed the retrieved data in blocksize chunks.

[Source]

     # File lib/net/ftp.rb, line 491
491:     def getbinaryfile(remotefile, localfile = File.basename(remotefile),
492:                       blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
493:       if @resume
494:         rest_offset = File.size?(localfile)
495:         f = open(localfile, "a")
496:       else
497:         rest_offset = nil
498:         f = open(localfile, "w")
499:       end
500:       begin
501:         f.binmode
502:         retrbinary("RETR " + remotefile, blocksize, rest_offset) do |data|
503:           f.write(data)
504:           yield(data) if block
505:         end
506:       ensure
507:         f.close
508:       end
509:     end
getdir()

Alias for pwd

Retrieves remotefile in ASCII (text) mode, storing the result in localfile. If a block is supplied, it is passed the retrieved data one line at a time.

[Source]

     # File lib/net/ftp.rb, line 516
516:     def gettextfile(remotefile, localfile = File.basename(remotefile), &block) # :yield: line
517:       f = open(localfile, "w")
518:       begin
519:         retrlines("RETR " + remotefile) do |line|
520:           f.puts(line)
521:           yield(line) if block
522:         end
523:       ensure
524:         f.close
525:       end
526:     end

Issues the HELP command.

[Source]

     # File lib/net/ftp.rb, line 777
777:     def help(arg = nil)
778:       cmd = "HELP"
779:       if arg
780:         cmd = cmd + " " + arg
781:       end
782:       sendcmd(cmd)
783:     end

Returns an array of file information in the directory (the output is like `ls -l`). If a block is given, it iterates through the listing.

[Source]

     # File lib/net/ftp.rb, line 620
620:     def list(*args, &block) # :yield: line
621:       cmd = "LIST"
622:       args.each do |arg|
623:         cmd = cmd + " " + arg
624:       end
625:       if block
626:         retrlines(cmd, &block)
627:       else
628:         lines = []
629:         retrlines(cmd) do |line|
630:           lines << line
631:         end
632:         return lines
633:       end
634:     end

Logs in to the remote host. The session must have been previously connected. If user is the string "anonymous" and the password is nil, a password of user@host is synthesized. If the acct parameter is not nil, an FTP ACCT command is sent following the successful login. Raises an exception on error (typically Net::FTPPermError).

[Source]

     # File lib/net/ftp.rb, line 372
372:     def login(user = "anonymous", passwd = nil, acct = nil)
373:       if user == "anonymous" and passwd == nil
374:         passwd = getaddress
375:       end
376:       
377:       resp = ""
378:       synchronize do
379:         resp = sendcmd('USER ' + user)
380:         if resp[0] == ?3
381:           resp = sendcmd('PASS ' + passwd)
382:         end
383:         if resp[0] == ?3
384:           resp = sendcmd('ACCT ' + acct)
385:         end
386:       end
387:       if resp[0] != ?2
388:         raise FTPReplyError, resp
389:       end
390:       @welcome = resp
391:     end
ls(*args)

Alias for list

Issues the MDTM command. TODO: more info.

[Source]

     # File lib/net/ftp.rb, line 767
767:     def mdtm(filename)
768:       resp = sendcmd("MDTM " + filename)
769:       if resp[0, 3] == "213"
770:         return resp[3 .. -1].strip
771:       end
772:     end

Creates a remote directory.

[Source]

     # File lib/net/ftp.rb, line 708
708:     def mkdir(dirname)
709:       resp = sendcmd("MKD " + dirname)
710:       return parse257(resp)
711:     end

Returns the last modification time of the (remote) file. If local is true, it is returned as a local time, otherwise it‘s a UTC time.

[Source]

     # File lib/net/ftp.rb, line 699
699:     def mtime(filename, local = false)
700:       str = mdtm(filename)
701:       ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i}
702:       return local ? Time.local(*ary) : Time.gm(*ary)
703:     end

Returns an array of filenames in the remote directory.

[Source]

     # File lib/net/ftp.rb, line 604
604:     def nlst(dir = nil)
605:       cmd = "NLST"
606:       if dir
607:         cmd = cmd + " " + dir
608:       end
609:       files = []
610:       retrlines(cmd) do |line|
611:         files.push(line)
612:       end
613:       return files
614:     end

Issues a NOOP command.

[Source]

     # File lib/net/ftp.rb, line 795
795:     def noop
796:       voidcmd("NOOP")
797:     end

Transfers localfile to the server in whatever mode the session is set (text or binary). See puttextfile and putbinaryfile.

[Source]

     # File lib/net/ftp.rb, line 584
584:     def put(localfile, remotefile = File.basename(localfile),
585:             blocksize = DEFAULT_BLOCKSIZE, &block)
586:       unless @binary
587:         puttextfile(localfile, remotefile, &block)
588:       else
589:         putbinaryfile(localfile, remotefile, blocksize, &block)
590:       end
591:     end

Transfers localfile to the server in binary mode, storing the result in remotefile. If a block is supplied, calls it, passing in the transmitted data in blocksize chunks.

[Source]

     # File lib/net/ftp.rb, line 546
546:     def putbinaryfile(localfile, remotefile = File.basename(localfile),
547:                       blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
548:       if @resume
549:         begin
550:           rest_offset = size(remotefile)
551:         rescue Net::FTPPermError
552:           rest_offset = nil
553:         end
554:       else
555:         rest_offset = nil
556:       end
557:       f = open(localfile)
558:       begin
559:         f.binmode
560:         storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
561:       ensure
562:         f.close
563:       end
564:     end

Transfers localfile to the server in ASCII (text) mode, storing the result in remotefile. If callback or an associated block is supplied, calls it, passing in the transmitted data one line at a time.

[Source]

     # File lib/net/ftp.rb, line 571
571:     def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line
572:       f = open(localfile)
573:       begin
574:         storlines("STOR " + remotefile, f, &block)
575:       ensure
576:         f.close
577:       end
578:     end

Returns the current remote directory.

[Source]

     # File lib/net/ftp.rb, line 723
723:     def pwd
724:       resp = sendcmd("PWD")
725:       return parse257(resp)
726:     end

Exits the FTP session.

[Source]

     # File lib/net/ftp.rb, line 788
788:     def quit
789:       voidcmd("QUIT")
790:     end

Renames a file on the server.

[Source]

     # File lib/net/ftp.rb, line 641
641:     def rename(fromname, toname)
642:       resp = sendcmd("RNFR " + fromname)
643:       if resp[0] != ?3
644:         raise FTPReplyError, resp
645:       end
646:       voidcmd("RNTO " + toname)
647:     end

Puts the connection into binary (image) mode, issues the given command, and fetches the data returned, passing it to the associated block in chunks of blocksize characters. Note that cmd is a server command (such as "RETR myfile").

[Source]

     # File lib/net/ftp.rb, line 399
399:     def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
400:       synchronize do
401:         voidcmd("TYPE I")
402:         conn = transfercmd(cmd, rest_offset)
403:         loop do
404:           data = conn.read(blocksize)
405:           break if data == nil
406:           yield(data)
407:         end
408:         conn.close
409:         voidresp
410:       end
411:     end

Puts the connection into ASCII (text) mode, issues the given command, and passes the resulting data, one line at a time, to the associated block. If no block is given, prints the lines. Note that cmd is a server command (such as "RETR myfile").

[Source]

     # File lib/net/ftp.rb, line 419
419:     def retrlines(cmd) # :yield: line
420:       synchronize do
421:         voidcmd("TYPE A")
422:         conn = transfercmd(cmd)
423:         loop do
424:           line = conn.gets
425:           break if line == nil
426:           if line[-2, 2] == CRLF
427:             line = line[0 .. -3]
428:           elsif line[-1] == ?\n
429:             line = line[0 .. -2]
430:           end
431:           yield(line)
432:         end
433:         conn.close
434:         voidresp
435:       end
436:     end

Obsolete

[Source]

     # File lib/net/ftp.rb, line 144
144:     def return_code
145:       $stderr.puts("warning: Net::FTP#return_code is obsolete and do nothing")
146:       return "\n"
147:     end

Obsolete

[Source]

     # File lib/net/ftp.rb, line 150
150:     def return_code=(s)
151:       $stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing")
152:     end

Removes a remote directory.

[Source]

     # File lib/net/ftp.rb, line 716
716:     def rmdir(dirname)
717:       voidcmd("RMD " + dirname)
718:     end

Sends a command and returns the response.

[Source]

     # File lib/net/ftp.rb, line 261
261:     def sendcmd(cmd)
262:       synchronize do
263:         putline(cmd)
264:         return getresp
265:       end
266:     end

WRITEME or make private

[Source]

     # File lib/net/ftp.rb, line 183
183:     def set_socket(sock, get_greeting = true)
184:       synchronize do
185:         @sock = sock
186:         if get_greeting
187:           voidresp
188:         end
189:       end
190:     end

Issues a SITE command.

[Source]

     # File lib/net/ftp.rb, line 802
802:     def site(arg)
803:       cmd = "SITE " + arg
804:       voidcmd(cmd)
805:     end

Returns the size of the given (remote) filename.

[Source]

     # File lib/net/ftp.rb, line 684
684:     def size(filename)
685:       voidcmd("TYPE I")
686:       resp = sendcmd("SIZE " + filename)
687:       if resp[0, 3] != "213" 
688:         raise FTPReplyError, resp
689:       end
690:       return resp[3..-1].strip.to_i
691:     end

Returns the status (STAT command).

[Source]

     # File lib/net/ftp.rb, line 757
757:     def status
758:       line = "STAT" + CRLF
759:       print "put: STAT\n" if @debug_mode
760:       @sock.send(line, Socket::MSG_OOB)
761:       return getresp
762:     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.

[Source]

     # File lib/net/ftp.rb, line 444
444:     def storbinary(cmd, file, blocksize, rest_offset = nil, &block) # :yield: data
445:       if rest_offset
446:         file.seek(rest_offset, IO::SEEK_SET)
447:       end
448:       synchronize do
449:         voidcmd("TYPE I")
450:         conn = transfercmd(cmd, rest_offset)
451:         loop do
452:           buf = file.read(blocksize)
453:           break if buf == nil
454:           conn.write(buf)
455:           yield(buf) if block
456:         end
457:         conn.close
458:         voidresp
459:       end
460:     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.

[Source]

     # File lib/net/ftp.rb, line 468
468:     def storlines(cmd, file, &block) # :yield: line
469:       synchronize do
470:         voidcmd("TYPE A")
471:         conn = transfercmd(cmd)
472:         loop do
473:           buf = file.gets
474:           break if buf == nil
475:           if buf[-2, 2] != CRLF
476:             buf = buf.chomp + CRLF
477:           end
478:           conn.write(buf)
479:           yield(buf) if block
480:         end
481:         conn.close
482:         voidresp
483:       end
484:     end

Returns system information.

[Source]

     # File lib/net/ftp.rb, line 732
732:     def system
733:       resp = sendcmd("SYST")
734:       if resp[0, 3] != "215"
735:         raise FTPReplyError, resp
736:       end
737:       return resp[4 .. -1]
738:     end

Sends a command and expect a response beginning with ‘2’.

[Source]

     # File lib/net/ftp.rb, line 271
271:     def voidcmd(cmd)
272:       synchronize do
273:         putline(cmd)
274:         voidresp
275:       end
276:     end

Private Instance methods

[Source]

     # File lib/net/ftp.rb, line 348
348:     def getaddress
349:       thishost = Socket.gethostname
350:       if not thishost.index(".")
351:         thishost = Socket.gethostbyname(thishost)[0]
352:       end
353:       if ENV.has_key?("LOGNAME")
354:         realuser = ENV["LOGNAME"]
355:       elsif ENV.has_key?("USER")
356:         realuser = ENV["USER"]
357:       else
358:         realuser = "anonymous"
359:       end
360:       return realuser + "@" + thishost
361:     end

[Source]

     # File lib/net/ftp.rb, line 210
210:     def getline
211:       line = @sock.readline # if get EOF, raise EOFError
212:       line.sub!(/(\r\n|\n|\r)\z/n, "")
213:       if @debug_mode
214:         print "get: ", sanitize(line), "\n"
215:       end
216:       return line
217:     end

[Source]

     # File lib/net/ftp.rb, line 220
220:     def getmultiline
221:       line = getline
222:       buff = line
223:       if line[3] == ?-
224:           code = line[0, 3]
225:         begin
226:           line = getline
227:           buff << "\n" << line
228:         end until line[0, 3] == code and line[3] != ?-
229:       end
230:       return buff << "\n"
231:     end

[Source]

     # File lib/net/ftp.rb, line 234
234:     def getresp
235:       @last_response = getmultiline
236:       @last_response_code = @last_response[0, 3]
237:       case @last_response_code
238:       when /\A[123]/
239:         return @last_response
240:       when /\A4/
241:         raise FTPTempError, @last_response
242:       when /\A5/
243:         raise FTPPermError, @last_response
244:       else
245:         raise FTPProtoError, @last_response
246:       end
247:     end

[Source]

     # File lib/net/ftp.rb, line 300
300:     def makepasv
301:       if @sock.peeraddr[0] == "AF_INET"
302:         host, port = parse227(sendcmd("PASV"))
303:       else
304:         host, port = parse229(sendcmd("EPSV"))
305:         #     host, port = parse228(sendcmd("LPSV"))
306:       end
307:       return host, port
308:     end

[Source]

     # File lib/net/ftp.rb, line 291
291:     def makeport
292:       sock = TCPServer.open(@sock.addr[3], 0)
293:       port = sock.addr[1]
294:       host = sock.addr[3]
295:       resp = sendport(host, port)
296:       return sock
297:     end

[Source]

     # File lib/net/ftp.rb, line 154
154:     def open_socket(host, port)
155:       if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
156:         @passive = true
157:         return SOCKSsocket.open(host, port)
158:       else
159:         return TCPSocket.open(host, port)
160:       end
161:     end

[Source]

     # File lib/net/ftp.rb, line 822
822:     def parse227(resp)
823:       if resp[0, 3] != "227"
824:         raise FTPReplyError, resp
825:       end
826:       left = resp.index("(")
827:       right = resp.index(")")
828:       if left == nil or right == nil
829:         raise FTPProtoError, resp
830:       end
831:       numbers = resp[left + 1 .. right - 1].split(",")
832:       if numbers.length != 6
833:         raise FTPProtoError, resp
834:       end
835:       host = numbers[0, 4].join(".")
836:       port = (numbers[4].to_i << 8) + numbers[5].to_i
837:       return host, port
838:     end

[Source]

     # File lib/net/ftp.rb, line 841
841:     def parse228(resp)
842:       if resp[0, 3] != "228"
843:         raise FTPReplyError, resp
844:       end
845:       left = resp.index("(")
846:       right = resp.index(")")
847:       if left == nil or right == nil
848:         raise FTPProtoError, resp
849:       end
850:       numbers = resp[left + 1 .. right - 1].split(",")
851:       if numbers[0] == "4"
852:         if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2"
853:           raise FTPProtoError, resp
854:         end
855:         host = numbers[2, 4].join(".")
856:         port = (numbers[7].to_i << 8) + numbers[8].to_i
857:       elsif numbers[0] == "6"
858:         if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2"
859:           raise FTPProtoError, resp
860:         end
861:         v6 = ["", "", "", "", "", "", "", ""]
862:         for i in 0 .. 7
863:           v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i,
864:                           numbers[(i * 2) + 3].to_i)
865:         end
866:         host = v6[0, 8].join(":")
867:         port = (numbers[19].to_i << 8) + numbers[20].to_i
868:       end 
869:       return host, port
870:     end

[Source]

     # File lib/net/ftp.rb, line 873
873:     def parse229(resp)
874:       if resp[0, 3] != "229"
875:         raise FTPReplyError, resp
876:       end
877:       left = resp.index("(")
878:       right = resp.index(")")
879:       if left == nil or right == nil
880:         raise FTPProtoError, resp
881:       end
882:       numbers = resp[left + 1 .. right - 1].split(resp[left + 1, 1])
883:       if numbers.length != 4
884:         raise FTPProtoError, resp
885:       end
886:       port = numbers[3].to_i
887:       host = (@sock.peeraddr())[3]
888:       return host, port
889:     end

[Source]

     # File lib/net/ftp.rb, line 892
892:     def parse257(resp)
893:       if resp[0, 3] != "257"
894:         raise FTPReplyError, resp
895:       end
896:       if resp[3, 2] != ' "'
897:         return ""
898:       end
899:       dirname = ""
900:       i = 5
901:       n = resp.length
902:       while i < n
903:         c = resp[i, 1]
904:         i = i + 1
905:         if c == '"'
906:           if i > n or resp[i, 1] != '"'
907:             break
908:           end
909:           i = i + 1
910:         end
911:         dirname = dirname + c
912:       end
913:       return dirname
914:     end

[Source]

     # File lib/net/ftp.rb, line 201
201:     def putline(line)
202:       if @debug_mode
203:         print "put: ", sanitize(line), "\n"
204:       end
205:       line = line + CRLF
206:       @sock.write(line)
207:     end

[Source]

     # File lib/net/ftp.rb, line 192
192:     def sanitize(s)
193:       if s =~ /^PASS /i
194:         return s[0, 5] + "*" * (s.length - 5)
195:       else
196:         return s
197:       end
198:     end

[Source]

     # File lib/net/ftp.rb, line 278
278:     def sendport(host, port)
279:       af = (@sock.peeraddr)[0]
280:       if af == "AF_INET"
281:         cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",")
282:       elsif af == "AF_INET6"
283:         cmd = sprintf("EPRT |2|%s|%d|", host, port)
284:       else
285:         raise FTPProtoError, host
286:       end
287:       voidcmd(cmd)
288:     end

[Source]

     # File lib/net/ftp.rb, line 311
311:     def transfercmd(cmd, rest_offset = nil)
312:       if @passive
313:         host, port = makepasv
314:         conn = open_socket(host, port)
315:         if @resume and rest_offset
316:           resp = sendcmd("REST " + rest_offset.to_s) 
317:           if resp[0] != ?3
318:             raise FTPReplyError, resp
319:           end
320:         end
321:         resp = sendcmd(cmd)
322:         # skip 2XX for some ftp servers
323:         resp = getresp if resp[0] == ?2
324:         if resp[0] != ?1
325:           raise FTPReplyError, resp
326:         end
327:       else
328:         sock = makeport
329:         if @resume and rest_offset
330:           resp = sendcmd("REST " + rest_offset.to_s) 
331:           if resp[0] != ?3
332:             raise FTPReplyError, resp
333:           end
334:         end
335:         resp = sendcmd(cmd)
336:         # skip 2XX for some ftp servers
337:         resp = getresp if resp[0] == ?2
338:         if resp[0] != ?1
339:           raise FTPReplyError, resp
340:         end
341:         conn = sock.accept
342:         sock.close
343:       end
344:       return conn
345:     end

[Source]

     # File lib/net/ftp.rb, line 250
250:     def voidresp
251:       resp = getresp
252:       if resp[0] != ?2
253:         raise FTPReplyError, resp
254:       end
255:     end

[Validate]