#!/usr/bin/ruby $: << File.expand_path('~/dev/nntp') require 'nntplib' require 'thread' require 'optparse' nthreads = 4 $nntpserver = 'news.free.fr' subdir = '.' xover = true do_dl = true cont = false startid = 0 startidpc = nil $noydec = false OptionParser.new { |opts| opts.on('-s', '--server host', 'news server') { |o| $nntpserver = o } opts.on('-n', '--nthreads N', 'number of parallel connections') { |o| nthreads = o.to_i } opts.on('-d', '--downloaddir dir', 'where to put downloaded files') { |o| subdir = o } opts.on('-v', '--verbose', 'show nntp raw messages') { $VERBOSE = true } opts.on('-x', '--xpat', 'use xpat (faster, but innacurate)') { xover = false } opts.on('-c', '--continue', 'do not redl existing files') { cont = true } opts.on('-r', '--nodecode', 'download files without ydecoding') { $noydec = true } opts.on('-i', '--startid N', 'start xpat/xover from it') { |o| (o[-1] == ?%) ? (startidpc = o.to_i) : (startid = o.to_i) } opts.on('--show', 'do not download') { do_dl = false } }.parse! raise 'group needed' unless group = ARGV.shift pattern = ARGV.shift Dir.mkdir subdir if not File.directory? subdir Dir.chdir subdir def start_dler(group, m, list, lister) Thread.new { s = NntpClient.new $nntpserver, group begin loop do while id = m.synchronize { list.shift } $stderr.print "#{list.length} \r" if $stderr.isatty if $noydec File.open("nntpgot.#{id}", 'w') { |fd| s.article(id) { |l| fd.puts l } } else s.dl_bin id, m end end break if list.empty? and not lister.alive? sleep 1 end ensure p s.quit if s.sock end } end m = Mutex.new list = [] lister = Thread.new { s = NntpClient.new $nntpserver, group begin if xover if startidpc foo, bar, min, max, baz = s.group(group).split.map { |i| i.to_i } startid = min + (max - min) * startidpc / 100 end s.xover("#{startid}-") { |l| id, subj = l.split("\t", 2) puts "#{id} #{subj.split("\t")[0]}" if id[-4..-1] == '0000' and $VERBOSE if subj =~ /#{pattern}/i subj = subj.split("\t", 2).first next if cont and Dir['?????*'].any? { |fn| subj.include? fn } puts "#{id} #{subj}" if subj =~ /\s\(0*1\/\d+\)/ m.synchronize { list << id.to_i } end } puts 'xover done' else s.xpat('subject', "#{startid}-", pattern) { |l| id, subj = l.split(' ', 2) next if cont and Dir.entries('.').any? { |fn| subj.include? fn } puts subj m.synchronize { list << id.to_i } } puts 'xpat done' end ensure s.quit end } if not do_dl lister.join exit end dlers = Array.new(nthreads-1) { start_dler(group, m, list, lister) } lister.join dlers << start_dler(group, m, list, lister) dlers.each { |t| t.join } system 'parrar-sh', '.'