update repository
[cmdllinux.git] / example_n_useful / ftp_dl / download2.rb
blob6f99794142fa46efb28a58afdbdc731d918a4c1a
1 require 'time'
2 require 'net/ftp'
4 module Net #:nodoc:
5   class FTP #:nodoc:
7     module List
8       def self.parse(*args)
9         Parser.parse(*args)
10       end
12       class ParserError < RuntimeError; end
14       class Parser
15         @@parsers = []
17         def initialize(raw)
18           @raw = raw
19         end
21         # The raw list entry string.
22         def raw
23           @raw ||= ''
24         end
25         alias_method :to_s, :raw
27         # The items basename (filename).
28         def basename
29           @basename ||= ''
30         end
32         # Looks like a directory, try CWD.
33         def dir?
34           !!(@dir ||= false)
35         end
37         # Looks like a file, try RETR.
38         def file?
39           !!(@file ||= false)
40         end
42         # Looks like a symbolic link.
43         def symlink?
44           !!(@symlink ||= false)
45         end
47         def mtime
48           @mtime
49         end
51         def filesize
52           @filesize
53         end
55         class << self
56           def inherited(klass) #:nodoc:
57             @@parsers << klass
58           end
60           def parse(raw)
61             @@parsers.reverse.each do |parser|
62               begin
63                 return parser.new(raw)
64               rescue ParserError
65                 next
66               end
67             end
68           end
69         end
70       end
72       class Unix < Parser
74         # Stolen straight from the ASF's commons Java FTP LIST parser library.
75         # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
76         REGEXP = %r{
77           ([bcdlfmpSs-])
78           (((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\+?\s+
79           (\d+)\s+
80           (\S+)\s+
81           (?:(\S+(?:\s\S+)*)\s+)?
82           (\d+)\s+
83           ((?:\d+[-/]\d+[-/]\d+)|(?:\S+\s+\S+))\s+
84           (\d+(?::\d+)?)\s+
85           (\S*)(\s*.*)
86         }x
88         # Parse a Unix like FTP LIST entries.
89         def initialize(raw)
90           super(raw)
91           match = REGEXP.match(raw.strip) or raise ParserError
93           case match[1]
94             when /d/    then @dir = true
95             when /l/    then @symlink = true
96             when /[f-]/ then @file = true
97             when /[bc]/ then # Do nothing with devices for now.
98             else ParserError 'Unknown LIST entry type.'
99           end
101           # TODO: Permissions, users, groups, date/time.
102           @filesize = match[18].to_i
103           @mtime = Time.parse("#{match[19]} #{match[20]}")
105           @basename = match[21].strip
107           # filenames with spaces will end up in the last match
108           @basename += match[22] unless match[22].nil?
110           # strip the symlink stuff we don't care about
111           @basename.sub!(/\s+\->.+$/, '') if @symlink
112         end
113       end
114     end
115   end
118 time = Time.new
119 SECONDS_PER_DAY = 60 * 60 * 24
120 time -= 120 * SECONDS_PER_DAY
122 ftp = Net::FTP.new('ftp.mozilla.org')
123 ftp.login
124 ftp.chdir('pub/firefox/releases/10.0.12esr/linux-i686/xpi')
126 lst = [ nil ]
128 ftp.list('*') do |f|
129     entry = Net::FTP::List.parse(f)
130     next unless (entry.mtime > time and entry.file?)
131     lst.insert(0, entry.basename)
134 for file in lst
135     next if file == nil
136     puts "Downloading #{file}"
137     ftp.getbinaryfile(file)
140 ftp.close