Class: Net::FTP

Inherits:
Object
  • Object
show all
Includes:
MonitorMixin
Defined in:
lib/net/ftp.rb

Overview

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.
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.
  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:

  • FTP.open

  • #getbinaryfile

  • #gettextfile

  • #putbinaryfile

  • #puttextfile

  • #chdir

  • #nlst

  • #size

  • #rename

  • #delete

Constant Summary collapse

FTP_PORT =

:stopdoc:

21
CRLF =
"\r\n"
DEFAULT_BLOCKSIZE =
4096
MDTM_REGEXP =

:nodoc:

/^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host = nil, user = nil, passwd = nil, acct = nil) ⇒ FTP

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.



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/net/ftp.rb', line 129

def initialize(host = nil, user = nil, passwd = nil, acct = nil)
  super()
  @binary = true
  @passive = false
  @debug_mode = false
  @resume = false
  if host
	connect(host)
	if user
	  (user, passwd, acct)
	end
  end
end

Instance Attribute Details

#binaryObject

When true, transfers are performed in binary mode. Default: true.



82
83
84
# File 'lib/net/ftp.rb', line 82

def binary
  @binary
end

#debug_modeObject

When true, all traffic to and from the server is written to $stdout. Default: false.



89
90
91
# File 'lib/net/ftp.rb', line 89

def debug_mode
  @debug_mode
end

#last_responseObject (readonly)

The server's last response.



103
104
105
# File 'lib/net/ftp.rb', line 103

def last_response
  @last_response
end

#last_response_codeObject (readonly) Also known as: lastresp

The server's last response code.



99
100
101
# File 'lib/net/ftp.rb', line 99

def last_response_code
  @last_response_code
end

#passiveObject

When true, the connection is in passive mode. Default: false.



85
86
87
# File 'lib/net/ftp.rb', line 85

def passive
  @passive
end

#resumeObject

Sets or retrieves the resume status, which decides whether incomplete transfers are resumed or restarted. Default: false.



93
94
95
# File 'lib/net/ftp.rb', line 93

def resume
  @resume
end

#welcomeObject (readonly)

The server's welcome message.



96
97
98
# File 'lib/net/ftp.rb', line 96

def welcome
  @welcome
end

Class Method Details

.open(host, user = nil, passwd = nil, acct = nil) ⇒ Object

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.



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/net/ftp.rb', line 111

def FTP.open(host, user = nil, passwd = nil, acct = nil)
  if block_given?
    ftp = new(host, user, passwd, acct)
    begin
      yield ftp
    ensure
      ftp.close
    end
  else
    new(host, user, passwd, acct)
  end
end

Instance Method Details

#abortObject

Aborts the previous command (ABOR command).



741
742
743
744
745
746
747
748
749
750
# File 'lib/net/ftp.rb', line 741

def abort
  line = "ABOR" + CRLF
  print "put: ABOR\n" if @debug_mode
  @sock.send(line, Socket::MSG_OOB)
  resp = getmultiline
  unless ["426", "226", "225"].include?(resp[0, 3])
	raise FTPProtoError, resp
  end
  return resp
end

#acct(account) ⇒ Object

Sends the ACCT command. TODO: more info.



594
595
596
597
# File 'lib/net/ftp.rb', line 594

def acct()
  cmd = "ACCT " + 
  voidcmd(cmd)
end

#chdir(dirname) ⇒ Object

Changes the (remote) directory.



664
665
666
667
668
669
670
671
672
673
674
675
676
677
# File 'lib/net/ftp.rb', line 664

def chdir(dirname)
  if dirname == ".."
	begin
	  voidcmd("CDUP")
	  return
	rescue FTPPermError => e
	  if e.message[0, 3] != "500"
 raise e
	  end
	end
  end
  cmd = "CWD " + dirname
  voidcmd(cmd)
end

#closeObject

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



809
810
811
# File 'lib/net/ftp.rb', line 809

def close
  @sock.close if @sock and not @sock.closed?
end

#closed?Boolean

Returns true iff the connection is closed.

Returns:

  • (Boolean)


816
817
818
# File 'lib/net/ftp.rb', line 816

def closed?
  @sock == nil or @sock.closed?
end

#connect(host, port = FTP_PORT) ⇒ Object

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.



170
171
172
173
174
175
176
177
178
# File 'lib/net/ftp.rb', line 170

def connect(host, port = FTP_PORT)
  if @debug_mode
	print "connect: ", host, ", ", port, "\n"
  end
  synchronize do
	@sock = open_socket(host, port)
	voidresp
  end
end

#delete(filename) ⇒ Object

Deletes a file on the server.



650
651
652
653
654
655
656
657
658
659
# File 'lib/net/ftp.rb', line 650

def delete(filename)
  resp = sendcmd("DELE " + filename)
  if resp[0, 3] == "250"
	return
  elsif resp[0] == ?5
	raise FTPPermError, resp
  else
	raise FTPReplyError, resp
  end
end

#get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

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



530
531
532
533
534
535
536
537
# File 'lib/net/ftp.rb', line 530

def get(remotefile, localfile = File.basename(remotefile),
 blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
  unless @binary
	gettextfile(remotefile, localfile, &block)
  else
	getbinaryfile(remotefile, localfile, blocksize, &block)
  end
end

#getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

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



489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/net/ftp.rb', line 489

def getbinaryfile(remotefile, localfile = File.basename(remotefile),
    blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
  if @resume
	rest_offset = File.size?(localfile)
	f = open(localfile, "a")
  else
	rest_offset = nil
	f = open(localfile, "w")
  end
  begin
	f.binmode
	retrbinary("RETR " + remotefile, blocksize, rest_offset) do |data|
	  f.write(data)
	  yield(data) if block
	end
  ensure
	f.close
  end
end

#gettextfile(remotefile, localfile = File.basename(remotefile), &block) ⇒ Object

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.



514
515
516
517
518
519
520
521
522
523
524
# File 'lib/net/ftp.rb', line 514

def gettextfile(remotefile, localfile = File.basename(remotefile), &block) # :yield: line
  f = open(localfile, "w")
  begin
	retrlines("RETR " + remotefile) do |line|
	  f.puts(line)
	  yield(line) if block
	end
  ensure
	f.close
  end
end

#help(arg = nil) ⇒ Object

Issues the HELP command.



775
776
777
778
779
780
781
# File 'lib/net/ftp.rb', line 775

def help(arg = nil)
  cmd = "HELP"
  if arg
	cmd = cmd + " " + arg
  end
  sendcmd(cmd)
end

#list(*args, &block) ⇒ Object Also known as: ls, dir

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.



618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
# File 'lib/net/ftp.rb', line 618

def list(*args, &block) # :yield: line
  cmd = "LIST"
  args.each do |arg|
	cmd = cmd + " " + arg
  end
  if block
	retrlines(cmd, &block)
  else
	lines = []
	retrlines(cmd) do |line|
	  lines << line
	end
	return lines
  end
end

#login(user = "anonymous", passwd = nil, acct = nil) ⇒ Object

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).



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/net/ftp.rb', line 368

def (user = "anonymous", passwd = nil, acct = nil)
  if user == "anonymous" and passwd == nil
	passwd = getaddress
  end
  
  resp = ""
  synchronize do
	resp = sendcmd('USER ' + user)
	if resp[0] == ?3
      raise FTPReplyError, resp if passwd.nil?
	  resp = sendcmd('PASS ' + passwd)
	end
	if resp[0] == ?3
      raise FTPReplyError, resp if acct.nil?
	  resp = sendcmd('ACCT ' + acct)
	end
  end
  if resp[0] != ?2
	raise FTPReplyError, resp
  end
  @welcome = resp
end

#mdtm(filename) ⇒ Object

Issues the MDTM command. TODO: more info.



765
766
767
768
769
770
# File 'lib/net/ftp.rb', line 765

def mdtm(filename)
  resp = sendcmd("MDTM " + filename)
  if resp[0, 3] == "213"
	return resp[3 .. -1].strip
  end
end

#mkdir(dirname) ⇒ Object

Creates a remote directory.



706
707
708
709
# File 'lib/net/ftp.rb', line 706

def mkdir(dirname)
  resp = sendcmd("MKD " + dirname)
  return parse257(resp)
end

#mtime(filename, local = false) ⇒ Object

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.



697
698
699
700
701
# File 'lib/net/ftp.rb', line 697

def mtime(filename, local = false)
  str = mdtm(filename)
  ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i}
  return local ? Time.local(*ary) : Time.gm(*ary)
end

#nlst(dir = nil) ⇒ Object

Returns an array of filenames in the remote directory.



602
603
604
605
606
607
608
609
610
611
612
# File 'lib/net/ftp.rb', line 602

def nlst(dir = nil)
  cmd = "NLST"
  if dir
	cmd = cmd + " " + dir
  end
  files = []
  retrlines(cmd) do |line|
	files.push(line)
  end
  return files
end

#noopObject

Issues a NOOP command.



793
794
795
# File 'lib/net/ftp.rb', line 793

def noop
  voidcmd("NOOP")
end

#put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

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



582
583
584
585
586
587
588
589
# File 'lib/net/ftp.rb', line 582

def put(localfile, remotefile = File.basename(localfile),
 blocksize = DEFAULT_BLOCKSIZE, &block)
  unless @binary
	puttextfile(localfile, remotefile, &block)
  else
	putbinaryfile(localfile, remotefile, blocksize, &block)
  end
end

#putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) ⇒ Object

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.



544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
# File 'lib/net/ftp.rb', line 544

def putbinaryfile(localfile, remotefile = File.basename(localfile),
    blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data
  if @resume
    begin
      rest_offset = size(remotefile)
    rescue Net::FTPPermError
      rest_offset = nil
    end
  else
	rest_offset = nil
  end
  f = open(localfile)
  begin
	f.binmode
	storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
  ensure
	f.close
  end
end

#puttextfile(localfile, remotefile = File.basename(localfile), &block) ⇒ Object

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.



569
570
571
572
573
574
575
576
# File 'lib/net/ftp.rb', line 569

def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line
  f = open(localfile)
  begin
	storlines("STOR " + remotefile, f, &block)
  ensure
	f.close
  end
end

#pwdObject Also known as: getdir

Returns the current remote directory.



721
722
723
724
# File 'lib/net/ftp.rb', line 721

def pwd
  resp = sendcmd("PWD")
  return parse257(resp)
end

#quitObject

Exits the FTP session.



786
787
788
# File 'lib/net/ftp.rb', line 786

def quit
  voidcmd("QUIT")
end

#rename(fromname, toname) ⇒ Object

Renames a file on the server.



639
640
641
642
643
644
645
# File 'lib/net/ftp.rb', line 639

def rename(fromname, toname)
  resp = sendcmd("RNFR " + fromname)
  if resp[0] != ?3
	raise FTPReplyError, resp
  end
  voidcmd("RNTO " + toname)
end

#retrbinary(cmd, blocksize, rest_offset = nil) ⇒ Object

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").



397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/net/ftp.rb', line 397

def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data
  synchronize do
	voidcmd("TYPE I")
	conn = transfercmd(cmd, rest_offset)
	loop do
	  data = conn.read(blocksize)
	  break if data == nil
	  yield(data)
	end
	conn.close
	voidresp
  end
end

#retrlines(cmd) ⇒ Object

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").



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'lib/net/ftp.rb', line 417

def retrlines(cmd) # :yield: line
  synchronize do
	voidcmd("TYPE A")
	conn = transfercmd(cmd)
	loop do
	  line = conn.gets
	  break if line == nil
	  if line[-2, 2] == CRLF
 line = line[0 .. -3]
	  elsif line[-1] == ?\n
 line = line[0 .. -2]
	  end
	  yield(line)
	end
	conn.close
	voidresp
  end
end

#return_codeObject

Obsolete



144
145
146
147
# File 'lib/net/ftp.rb', line 144

def return_code
  $stderr.puts("warning: Net::FTP#return_code is obsolete and do nothing")
  return "\n"
end

#return_code=(s) ⇒ Object

Obsolete



150
151
152
# File 'lib/net/ftp.rb', line 150

def return_code=(s)
  $stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing")
end

#rmdir(dirname) ⇒ Object

Removes a remote directory.



714
715
716
# File 'lib/net/ftp.rb', line 714

def rmdir(dirname)
  voidcmd("RMD " + dirname)
end

#sendcmd(cmd) ⇒ Object

Sends a command and returns the response.



261
262
263
264
265
266
# File 'lib/net/ftp.rb', line 261

def sendcmd(cmd)
  synchronize do
	putline(cmd)
	return getresp
  end
end

#set_socket(sock, get_greeting = true) ⇒ Object

WRITEME or make private



183
184
185
186
187
188
189
190
# File 'lib/net/ftp.rb', line 183

def set_socket(sock, get_greeting = true)
  synchronize do
	@sock = sock
	if get_greeting
	  voidresp
	end
  end
end

#site(arg) ⇒ Object

Issues a SITE command.



800
801
802
803
# File 'lib/net/ftp.rb', line 800

def site(arg)
  cmd = "SITE " + arg
  voidcmd(cmd)
end

#size(filename) ⇒ Object

Returns the size of the given (remote) filename.



682
683
684
685
686
687
688
689
# File 'lib/net/ftp.rb', line 682

def size(filename)
  voidcmd("TYPE I")
  resp = sendcmd("SIZE " + filename)
  if resp[0, 3] != "213" 
	raise FTPReplyError, resp
  end
  return resp[3..-1].strip.to_i
end

#statusObject

Returns the status (STAT command).



755
756
757
758
759
760
# File 'lib/net/ftp.rb', line 755

def status
  line = "STAT" + CRLF
  print "put: STAT\n" if @debug_mode
  @sock.send(line, Socket::MSG_OOB)
  return getresp
end

#storbinary(cmd, file, blocksize, rest_offset = nil, &block) ⇒ Object

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.



442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/net/ftp.rb', line 442

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
	voidresp
  end
end

#storlines(cmd, file, &block) ⇒ Object

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.



466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/net/ftp.rb', line 466

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
	voidresp
  end
end

#systemObject

Returns system information.



730
731
732
733
734
735
736
# File 'lib/net/ftp.rb', line 730

def system
  resp = sendcmd("SYST")
  if resp[0, 3] != "215"
	raise FTPReplyError, resp
  end
  return resp[4 .. -1]
end

#voidcmd(cmd) ⇒ Object

Sends a command and expect a response beginning with '2'.



271
272
273
274
275
276
# File 'lib/net/ftp.rb', line 271

def voidcmd(cmd)
  synchronize do
	putline(cmd)
	voidresp
  end
end