#!/usr/local/bin/ruby

# $Id$
# $Source$

require 'date'
require 'getoptlong'
require 'news/article'
require 'news/newsrc'
require 'tempfile'


###########################################################################

Debuglevel = 0

def save_file(dir, name, data)
	print "savename: #{name}\n" if Debuglevel > 1
	nname = name.gsub(/\//, "-")
	print "nname: #{nname}\n" if Debuglevel > 1
	nname.sub!(/\s*$/, "")
	nname.sub!(/^\s*/, "")
	newname = nname
	count = 1
	d = Date.today
	date = "#{d.year}#{d.month}#{d.mday}"
	while FileTest.exists?("#{dir}/#{newname}")
		newname = "#{nname}-<#{date}.#{count}>"
		count += 1
	end
	print "name: #{newname}\n" if Debuglevel > 1

	case data.type.to_s
		when "String"
			if File.rename(data, "#{dir}/#{newname}")
				print "	Saving as: '#{newname}'\n"
			else
				print "couldn't rename tempfile\n"
				return false
			end
		when "Array"
			if file = File.new("#{dir}/#{newname}", "w", "0644")
				print "	Saving as: '#{newname}'\n"
				data.collect{|i| file.print "#{i}"}
			else
				print "couldn't open file for writeing\n"
				return false
			end
		else
			print "EEEEPS Can't save data of type: #{data.type.to_s}\n"
			return false
	end
	return true
end

def parse_options(options)
	begin
	opts = GetoptLong.new(
		[ "-I", "--include",		GetoptLong::REQUIRED_ARGUMENT ],
		[ "-c", "--configfile",		GetoptLong::REQUIRED_ARGUMENT ],
		[ "-L", "--longname",		GetoptLong::NO_ARGUMENT ],
		[ "-M", "--multipart",		GetoptLong::NO_ARGUMENT ],
		[ "-S", "--singlepart",		GetoptLong::NO_ARGUMENT ],
		[ "-T", "--test",		GetoptLong::NO_ARGUMENT ],
		[ "-X", "--exclude",		GetoptLong::REQUIRED_ARGUMENT ],
		[ "-g", "--greedy",		GetoptLong::NO_ARGUMENT ]
	)
	opts.quiet=true

	opts.each do |opt, arg|
		options[opt] = arg
	end

	rescue
		print "#{opts.error_message}\n"
		print "\nUsage:\n"
		exit
	end

	return options
end

def parse_config(default = {})
	file = File.new("#{default[\"-c\"]}")
	lines = file.readlines

	i = 0
	group = ""
	grouparr = []
	@config = {}

	lines.collect!{|x|
		x.sub!(/^\s*/, "")
		x.sub!(/\#.*$/, "")
		x.chomp
	}
	while i < lines.length
		line = lines[i]
		while line.sub!(/\s*\\$/, "") != nil
			line += lines[i+1]
			i += 1
		end
		line.sub!(/\s*$/, "")
		i += 1
		if line =~ /^OPT_(.*?)=(.*)/
			line = "-#{$1}=#{$2}"
		end
		print "#{i}: #{line}\n" if Debuglevel > 1
		if line =~ /(.*?)\s*\+=\s*(.*)/
			if group == ""
				if default.has_key?($1)
					default[$1] += $2
				else
					default[$1] = $2
				end
			else
				grouparr.collect{|g|
					if @config[g].has_key?($1)
						@config[g][$1] += $2
					elsif default.has_key?($1)
						@config[g][$1] = default[$1] + $2
					else
						@config[g][$1] = $2
					end
				}
			end
		elsif line =~ /(.*?)\s*=\s*(.*)/
			if group == ""
				default[$1] = $2
			else
				grouparr.collect{|g|
					@config[g][$1] = $2
				}
			end
		elsif line =~ /(.*?)\s*\{/
			group = $1
			grouparr = group.split('|')
			grouparr.collect{|g|
				@config[g] = {} unless @config.has_key?(g)
			}
		elsif line =~ /^}$/
			default.each_key{|x|
				grouparr.collect{|g|
					@config[g][x] = default[x] unless @config[g].has_key?(x)
				}
			}
			group = ""
			grouparr = []
		elsif line =~ /^$/
			next
		else
			print "Error parsing config on line: #{i}\n"
			exit
		end
	end

	if group != ""
		print "Error parsing config: group not terminated on line #{i}\n"
		exit
	end

	if Debuglevel > 2
		@config.each_key{|x|
			print "Group: #{x}\n"
			@config[x].each_key{|y|
				print "Key: '#{y}' => Value: '#{@config[x][y]}'\n"
			}
		}
	end
	return true
end

def check_config
	@config.each_key {|i|
		unless @config[i].has_key?("-I")
			print "No inclusions given for group #{i}. Won't match anything.\n"
			exit
		end
		unless @config[i].has_key?("DATADIR")
			@config[i]["DATADIR"] ="."
		end
		unless @config[i].has_key?("PERMISSION")
			@config[i]["PERMISSION"] = "0755"
		end
	}
end

def get_single(subj)
	print "	Singlepart!\n"
	body = @articles.get_group_body(subj)
	if @articles.is_uuencoded(body)
		mode, filename, body = @articles.uudecode(body)
	else
		print "Not UUencoded!\n"
		return false
	end
	return mode, filename, body
end

def get_multi(subj, group)
	print "	Multipart!\n"
	if @config[group]["TEMPDIR"] == nil or @config[group]["TEMPDIR"] == ""
		body = @articles.get_group_body(subj)
		if @articles.is_uuencoded(body)
			mode, filename, body = @articles.uudecode(body)
		else
			print "Multipart article not UUencoded!\n"
			return false
		end
	else
		body = @articles.get_group_body_first(subj)
		next if body == false
		if @articles.is_uuencoded(body)
			file = Tempfile.new("riptmp", @config[group]["TEMPDIR"])
			body.collect{|x| file.print "#{x}\n"}
			next unless @articles.get_group_body_rest(subj, file)
			fileout = Tempfile.new("riptmp", @config[group]["TEMPDIR"])
			mode, filename, body = @articles.uudecode(file, fileout)
			body = fileout.path
			file.close
			fileout.close
		else
			print "Multipart article not UUencoded!\n"
			return false
		end
	end
	return mode, filename, body
end

def output_data(subject, mode, filename="", body="")
	if mode
		group = @articles.get_groupname
		print "	mode: #{mode}\n" if Debuglevel > 0
		print "	Filename: '#{filename}'\n" if Debuglevel > 0
		if @config[group].has_key?("-L") and @config[group]["-L"]
			print "longname\n" if Debuglevel > 1
			if save_file("#{@config[group]["DATADIR"]}/#{group}", subject, body)
				@articles.group_update_newsrc(subject)
				@articles.save_newsrc unless @config[group].has_key?("-T") and @config[group]["-T"]
			end
		else
			print "shortname\n" if Debuglevel > 1
			if save_file("#{@config[group]["DATADIR"]}/#{group}", filename, body)
				@articles.group_update_newsrc(subject)
				@articles.save_newsrc unless @config[group].has_key?("-T") and @config[group]["-T"]
			end
		end
	else
		return false
	end
	return true
end

#############################################################################################

defaults = {'-c' => '.ripnewsrc'}
defaults = parse_options(defaults)
parse_config(defaults)
check_config

if Debuglevel > 2
	@config.each_key{|i|
		print "Group: #{i}\n"
		@config[i].each_key{|j|
			print "Opt: #{j} val: #{@config[i][j]}\n"
		}
	}
end

for group in @config.keys.sort
	print "Getting articles for #{group}\n"
	@articles = Article.new(@config[group]["NNTPSERVER"], group, @config[group]["NEWSRCNAME"])
	@articles.get_articles(@config[group]["CACHEDIR"])

	unless FileTest.directory?("#{@config[group]["DATADIR"]}/#{group}") or
			Dir.mkdir("#{@config[group]["DATADIR"]}/#{group}", @config[group]["PERMISSION"].oct)
		print "eeeps, couldn't create dir\n"
		exit
	end
	for i in @articles.get_group_subjects
		print "#{i}\n" if Debuglevel > 2
		if !(@config[group].has_key?("-X") and i =~ /#{@config[group]["-X"]}/) and
		   i =~ /#{@config[group]["-I"]}/
			print "Match: #{i}\n" if Debuglevel > 0
			if @articles.group_is_complete(i)
				print "	Fetching: #{i}\n"
				if @articles.group_is_singlepart(i)
					mode, filename, body = get_single(i)
				elsif @articles.group_is_multipart(i)
					mode, filename, body = get_multi(i, group)
				end
				output_data(i, mode, filename, body)
			else
				print "	Not complete: #{i}\n"
			end
		end
	end
	@articles.quit
end
