2002-04-27 20:31:59 +00:00
|
|
|
#################################
|
|
|
|
|
#
|
2002-11-05 09:33:41 +00:00
|
|
|
# $Dwarf: newsrc.rb,v 1.10 2002/08/01 11:50:09 ward Exp $
|
2002-04-27 20:34:15 +00:00
|
|
|
# $Source$
|
|
|
|
|
#
|
2002-04-27 20:31:59 +00:00
|
|
|
# newsrc.rb
|
|
|
|
|
# ported from Perl code by Ward Wouts
|
|
|
|
|
#
|
|
|
|
|
# (C) 2001, Ward Wouts
|
|
|
|
|
#
|
|
|
|
|
#################################
|
|
|
|
|
|
|
|
|
|
require "set/intspan"
|
|
|
|
|
|
|
|
|
|
module News
|
|
|
|
|
|
|
|
|
|
class Newsrc
|
|
|
|
|
|
|
|
|
|
def initialize(file=nil)
|
|
|
|
|
@newsrc = { "group" => Hash.new, "list" => Array.new }
|
|
|
|
|
if file
|
|
|
|
|
unless load(file)
|
|
|
|
|
print "Can't load #{file}\n"
|
|
|
|
|
exit
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def load(file=nil)
|
|
|
|
|
file = "#{ENV['HOME']}/.newsrc" unless file
|
|
|
|
|
@newsrc["file"] = file
|
|
|
|
|
@newsrc["group"] = {}
|
|
|
|
|
@newsrc["list"] = []
|
|
|
|
|
|
2002-05-05 14:51:02 +00:00
|
|
|
if FileTest.file?( "#{file}" ) and FileTest.readable?( "#{file}" )
|
|
|
|
|
lines = IO.readlines("#{file}")
|
|
|
|
|
import_rc(lines)
|
|
|
|
|
end
|
2002-04-27 20:31:59 +00:00
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def import_rc(lines)
|
|
|
|
|
@newsrc["group"] = {}
|
|
|
|
|
@newsrc["list"] = []
|
|
|
|
|
linenumber = 1
|
|
|
|
|
for line in lines
|
|
|
|
|
parse(line)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def parse(line)
|
|
|
|
|
unless line =~ /^([^!:]+)([!:])\s(.*)$/x
|
|
|
|
|
print "Newsrc.parse: Bad newsrc line: #{line}\n"
|
|
|
|
|
exit
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
name = $1
|
|
|
|
|
mark = $2
|
|
|
|
|
articles = $3
|
|
|
|
|
|
|
|
|
|
unless Set::IntSpan.valid(articles)
|
|
|
|
|
print "Newsrc.parse: Bad article list: #{line}\n"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
group = { "name" => name, "subscribed" => (mark == ":"),
|
|
|
|
|
"articles" => Set::IntSpan.new(articles)}
|
|
|
|
|
|
|
|
|
|
@newsrc["group"][name] = group
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def save
|
|
|
|
|
unless @newsrc.has_key?("file")
|
|
|
|
|
@newsrc["file"] = "#{$ENV['HOME']}/.newsrc"
|
|
|
|
|
end
|
|
|
|
|
save_as(@newsrc["file"])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def save_as(file)
|
|
|
|
|
if FileTest.exists?("#{file}")
|
|
|
|
|
begin
|
|
|
|
|
File.rename(file, "#{file}.bak")
|
|
|
|
|
rescue
|
|
|
|
|
print "Can't rename #{file}, #{file}.bak: #{$!}\n"
|
|
|
|
|
exit
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
begin
|
|
|
|
|
newsrc = File.new(file, "w")
|
|
|
|
|
rescue
|
|
|
|
|
print "Can't open #{file}: #{$!}\n"
|
|
|
|
|
exit
|
|
|
|
|
end
|
|
|
|
|
@newsrc["file"] = file
|
|
|
|
|
for group in @newsrc["list"]
|
|
|
|
|
newsrc.print format(group)
|
|
|
|
|
end
|
2002-04-30 21:12:16 +00:00
|
|
|
newsrc.close
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def format(group)
|
|
|
|
|
name = group["name"]
|
|
|
|
|
sub = group["subscribed"] ? ':' : '!'
|
|
|
|
|
articles = group["articles"].run_list
|
2002-04-28 22:05:20 +00:00
|
|
|
#space = articles ? ' ' : ''
|
|
|
|
|
#return "#{name}#{sub}#{space}#{articles}\n"
|
|
|
|
|
return "#{name}#{sub} #{articles}\n"
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def export_rc
|
|
|
|
|
lines = @newsrc["list"].collect{ |group|
|
|
|
|
|
name = group["name"]
|
|
|
|
|
sub = group["subscribed"] ? ':' : '!'
|
|
|
|
|
articles = group["articles"].run_list
|
|
|
|
|
space = articles ? ' ' : ''
|
|
|
|
|
"#{name}#{sub}#{space}#{articles}\n" }
|
|
|
|
|
return lines
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def add_group(name, options)
|
|
|
|
|
|
|
|
|
|
if @newsrc["group"].has_key?(name)
|
|
|
|
|
options.has_key?("replace") or return false
|
|
|
|
|
del_group(name)
|
|
|
|
|
end
|
|
|
|
|
group = {"name" => name,
|
2002-04-28 11:28:04 +00:00
|
|
|
"subscribed" => true,
|
2002-04-27 20:31:59 +00:00
|
|
|
"articles" => Set::IntSpan.new }
|
|
|
|
|
|
|
|
|
|
@newsrc["group"][name] = group
|
|
|
|
|
_insert(group, options)
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def move_group(name, options)
|
|
|
|
|
if @newsrc["group"].has_key?(name)
|
|
|
|
|
group = @newsrc["group"][name]
|
|
|
|
|
else
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
@newsrc["list"] = @newsrc["list"].delete_if{|x| x["name"] == name}
|
|
|
|
|
|
|
|
|
|
_insert(group, options)
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def _insert(group, options)
|
|
|
|
|
list = @newsrc["list"]
|
|
|
|
|
|
|
|
|
|
where = ""
|
|
|
|
|
arg = ""
|
|
|
|
|
if options.has_key?("where")
|
|
|
|
|
where = options["where"]
|
|
|
|
|
end
|
|
|
|
|
arg = where.slice!(1) if where.type.to_s == "Array"
|
|
|
|
|
|
|
|
|
|
case where.to_s
|
|
|
|
|
when "first"
|
|
|
|
|
@newsrc["list"].unshift(group)
|
|
|
|
|
when "last"
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
2002-04-27 20:31:59 +00:00
|
|
|
when ""
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group) # default
|
2002-04-27 20:31:59 +00:00
|
|
|
when "alpha"
|
|
|
|
|
alpha(group)
|
|
|
|
|
when "before"
|
|
|
|
|
before(group, arg)
|
|
|
|
|
when "after"
|
|
|
|
|
after(group, arg)
|
|
|
|
|
when "number"
|
|
|
|
|
number(group, arg)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def alpha (group)
|
|
|
|
|
name = group["name"]
|
|
|
|
|
for i in (0...@newsrc["list"].length)
|
|
|
|
|
if ((name <=> @newsrc["list"][i]["name"]) == -1)
|
|
|
|
|
upper = @newsrc["list"].slice!(i..@newsrc["list"].length)
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
|
|
|
|
@newsrc["list"].push(upper)
|
2002-04-27 20:31:59 +00:00
|
|
|
return;
|
|
|
|
|
end
|
|
|
|
|
end
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def before(group, before)
|
|
|
|
|
name = group["name"]
|
|
|
|
|
for i in (0...@newsrc["list"].length)
|
|
|
|
|
if (@newsrc["list"][i]["name"] == before.to_s)
|
|
|
|
|
upper = @newsrc["list"].slice!(i..@newsrc["list"].length)
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
|
|
|
|
@newsrc["list"].push(upper)
|
2002-04-27 20:31:59 +00:00
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def after(group, after)
|
|
|
|
|
name = group["name"]
|
|
|
|
|
|
|
|
|
|
for i in (0...@newsrc["list"].length)
|
|
|
|
|
if (@newsrc["list"][i]["name"] == after.to_s)
|
|
|
|
|
upper = @newsrc["list"].slice!((i+1)..@newsrc["list"].length)
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
|
|
|
|
@newsrc["list"].push(upper)
|
2002-04-27 20:31:59 +00:00
|
|
|
return;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def number(group, offset)
|
|
|
|
|
offset = @newsrc["list"].length if offset[0] > @newsrc["list"].length
|
|
|
|
|
upper = @newsrc["list"].slice!(offset..@newsrc["list"].length)
|
2002-08-01 09:23:15 +00:00
|
|
|
@newsrc["list"].push(group)
|
|
|
|
|
@newsrc["list"].push(upper)
|
2002-04-27 20:31:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def del_group(name)
|
|
|
|
|
if @newsrc["group"].has_key?(name)
|
|
|
|
|
group = @newsrc["group"][name]
|
|
|
|
|
else
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
@newsrc["group"].delete(name)
|
|
|
|
|
@newsrc["list"] = @newsrc["list"].delete_if{|x| x["name"] == name}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def subscribe(name, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
@newsrc["group"][name]["subscribed"] = true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def unsubscribe(name, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
@newsrc["group"][name]["subscribed"] = false
|
|
|
|
|
end
|
|
|
|
|
|
2002-04-27 23:42:50 +00:00
|
|
|
def mark(name, article, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
@newsrc["group"][name]["articles"].insert(article)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def mark_list(name, list, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
articles = @newsrc["group"][name]["articles"].union(list)
|
|
|
|
|
@newsrc["group"][name]["articles"] = articles
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def mark_range(name, from, to, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
range = Set::IntSpan.new("#{from}-#{to}")
|
|
|
|
|
articles = @newsrc["group"][name]["articles"].union(range)
|
|
|
|
|
@newsrc["group"][name]["articles"] = articles
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def unmark(name, article, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
@newsrc["group"][name]["articles"].remove(article)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def unmark_list(name, list, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
articles = @newsrc["group"][name]["articles"].diff(list)
|
|
|
|
|
@newsrc["group"][name]["articles"] = articles
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def unmark_range(name, from, to, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
range = Set::IntSpan.new("#{from}-#{to}")
|
|
|
|
|
articles = @newsrc["group"][name]["articles"].diff(range)
|
|
|
|
|
@newsrc["group"][name]["articles"] = articles
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def exists(name)
|
|
|
|
|
return @newsrc["group"].has_key?(name) ? true : false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def subscribed(name)
|
|
|
|
|
exists(name) and @newsrc["group"][name]["subscribed"]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def marked(name, article)
|
|
|
|
|
exists(name) and @newsrc["group"][name]["articles"].member(article)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def num_groups
|
|
|
|
|
return @newsrc["list"].length
|
|
|
|
|
end
|
|
|
|
|
|
2002-04-28 11:28:04 +00:00
|
|
|
def groups
|
2002-04-28 15:04:19 +00:00
|
|
|
list = @newsrc["list"].dup
|
|
|
|
|
list.collect!{|x| x["name"]}
|
2002-04-28 11:28:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def sub_groups
|
2002-04-28 15:04:19 +00:00
|
|
|
list = @newsrc["list"].dup
|
|
|
|
|
list.collect!{|x| x["subscribed"] ? x["name"] : nil}.compact!
|
2002-04-28 11:28:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def unsub_groups
|
2002-04-28 15:04:19 +00:00
|
|
|
list = @newsrc["list"].dup
|
|
|
|
|
list.collect!{|x| x["subscribed"] ? nil : x["name"]}.compact!
|
2002-04-28 11:28:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def marked_articles(name, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
return @newsrc["group"][name]["articles"].elements
|
|
|
|
|
end
|
2002-04-27 23:42:50 +00:00
|
|
|
|
2002-04-28 11:28:04 +00:00
|
|
|
def unmarked_articles(name, from, to, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
range = Set::IntSpan.new("#{from}-#{to}")
|
2002-04-28 15:04:19 +00:00
|
|
|
return range.diff(@newsrc["group"][name]["articles"]).elements
|
2002-04-28 11:28:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def get_articles(name, options = {"where" => ""})
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
@newsrc["group"][name]["articles"].run_list
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def set_articles(name, articles, options = {"where" => ""})
|
|
|
|
|
Set::IntSpan.valid(articles) or return false
|
|
|
|
|
set = Set::IntSpan.new(articles)
|
|
|
|
|
set.finite or return false
|
|
|
|
|
min = set.min
|
|
|
|
|
min != nil and min < 0 and return false
|
|
|
|
|
unless @newsrc["group"].has_key?(name)
|
|
|
|
|
add_group(name, options)
|
|
|
|
|
end
|
|
|
|
|
@newsrc["group"][name]["articles"] = set
|
|
|
|
|
return true
|
|
|
|
|
end
|
2002-04-27 23:42:50 +00:00
|
|
|
|
2002-04-27 20:31:59 +00:00
|
|
|
end # class
|
|
|
|
|
|
|
|
|
|
end # module
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# TODO
|
|
|
|
|
# Do not kill an item until it's tested!
|
|
|
|
|
|
|
|
|
|
# [x] new
|
|
|
|
|
# [x] load
|
|
|
|
|
# [ ] _scan # Initializes a Newsrc object from a string. Used for testing.
|
|
|
|
|
# [x] import_rc
|
|
|
|
|
# [x] parse # parses a single line from a newsrc file
|
|
|
|
|
# [x] save
|
|
|
|
|
# [x] save_as
|
|
|
|
|
# [x] format
|
|
|
|
|
# [x] export_rc
|
|
|
|
|
# [ ] _dump # Formats a Newsrc object to a string. Used for testing
|
|
|
|
|
# [x] add_group
|
|
|
|
|
# [x] move_group
|
|
|
|
|
# [x] Splice(\@$$@) # heet nu number en is simpeler
|
|
|
|
|
# [x] _insert
|
|
|
|
|
# [x] Alpha
|
|
|
|
|
# [x] Before
|
|
|
|
|
# [x] After
|
|
|
|
|
# [x] del_group
|
|
|
|
|
# [x] subscribe
|
|
|
|
|
# [x] unsubscribe
|
2002-04-27 23:42:50 +00:00
|
|
|
# [x] mark
|
|
|
|
|
# [x] mark_list
|
|
|
|
|
# [x] mark_range
|
|
|
|
|
# [x] unmark
|
|
|
|
|
# [x] unmark_list
|
|
|
|
|
# [x] unmark_range
|
|
|
|
|
# [x] exists
|
|
|
|
|
# [x] subscribed
|
|
|
|
|
# [x] marked
|
|
|
|
|
# [x] num_groups
|
2002-04-28 11:28:04 +00:00
|
|
|
# [x] groups
|
|
|
|
|
# [x] sub_groups
|
|
|
|
|
# [x] unsub_groups
|
|
|
|
|
# [x] marked_articles
|
2002-04-28 15:04:19 +00:00
|
|
|
# [x] unmarked_articles
|
2002-04-28 11:28:04 +00:00
|
|
|
# [x] get_articles
|
|
|
|
|
# [x] set_articles
|