previous commits served only to screw things up. now everything works
and messages are lovingly threaded in the correct manner
+x bugfix: threading broken
x bugfix: thread ordering in thread-index-mode sometimes jumps around with 'M'
x forwards optionally include attachments
x flesh out gpg integration: sign & encrypt outgoing
x bugfix: thread ordering in thread-index-mode sometimes jumps around with 'M'
x forwards optionally include attachments
x flesh out gpg integration: sign & encrypt outgoing
## unused
def dump f=$stdout
## unused
def dump f=$stdout
- f.puts "=== start thread #{self} with #{@containers.length} trees ==="
- @containers.each { |c| c.dump_recursive f }
+ f.puts "=== start thread with #{@containers.length} trees ==="
+ @containers.each { |c| c.dump_recursive f; f.puts }
f.puts "=== end thread ==="
end
f.puts "=== end thread ==="
end
def to_s
"<thread containing: #{@containers.join ', '}>"
end
def to_s
"<thread containing: #{@containers.join ', '}>"
end
-
- def prune_dangling_container_trees!
- @containers.delete_if { |c| c.dangling? }
- end
end
## recursive structure used internally to represent message trees as
end
## recursive structure used internally to represent message trees as
- def dangling?
- if @children.any? { |c| !c.empty? }
- false
- elsif @children.any? { |c| !c.dangling? }
- false
- else
- true
- end
- end
-
def descendant_of? o
if o == self
true
def descendant_of? o
if o == self
true
f.print " " * indent
f.print "+->"
end
f.print " " * indent
f.print "+->"
end
- line = #"[#{useful? ? 'U' : ' '}] " +
+ line = "[#{thread.nil? ? ' ' : '*'}] " + #"[#{useful? ? 'U' : ' '}] " +
- "[#{thread}] #{@message.subj} " ##{@message.refs.inspect} / #{@message.replytos.inspect}"
+ message.subj ##{@message.refs.inspect} / #{@message.replytos.inspect}"
## one thread, even if they don't reference each other. This is
## helpful for crappy MUAs that don't set In-reply-to: or References:
## headers, but means that messages may be threaded unnecessarily.
## one thread, even if they don't reference each other. This is
## helpful for crappy MUAs that don't set In-reply-to: or References:
## headers, but means that messages may be threaded unnecessarily.
+##
+## The following invariants are maintained: every Thread has at least one
+## Container tree, and every Container tree has at least one Message.
class ThreadSet
attr_reader :num_messages
bool_reader :thread_by_subj
class ThreadSet
attr_reader :num_messages
bool_reader :thread_by_subj
def thread_for m; thread_for_id m.id end
def contains? m; contains_id? m.id end
def thread_for m; thread_for_id m.id end
def contains? m; contains_id? m.id end
- def threads; prune_empty_threads.values end
- def size; prune_empty_threads.size end
+ def threads; @threads.values end
+ def size; @threads.size end
@threads.each do |s, t|
f.puts "**********************"
f.puts "** for subject #{s} **"
@threads.each do |s, t|
f.puts "**********************"
f.puts "** for subject #{s} **"
## link two containers
def link p, c, overwrite=false
if p == c || p.descendant_of?(c) || c.descendant_of?(p) # would create a loop
## link two containers
def link p, c, overwrite=false
if p == c || p.descendant_of?(c) || c.descendant_of?(p) # would create a loop
-# puts "*** linking parent #{p} and child #{c} would create a loop"
+ #puts "*** linking parent #{p.id} and child #{c.id} would create a loop"
- if c.parent.nil? || overwrite
- remove_container c
- p.children << c
- c.parent = p
+ #puts "in link for #{p.id} to #{c.id}, perform? #{c.parent.nil?} || #{overwrite}"
+
+ return unless c.parent.nil? || overwrite
+ remove_container c
+ p.children << c
+ c.parent = p
+
+ ## if the child was previously a top-level container, but now is not,
+ ## ditch our thread and kill it if necessary
+ if c.thread && !c.root?
+ c.thread.drop c
+ @threads.delete_if { |k, v| v == c.thread } if c.thread.empty?
+ c.thread = nil
end
end
private :link
def remove_container c
c.parent.children.delete c if c.parent # remove from tree
end
end
private :link
def remove_container c
c.parent.children.delete c if c.parent # remove from tree
- thread = c.root.thread # find containing thread
- if thread
- thread.prune_dangling_container_trees!
- c.root.thread = nil
- end
end
private :remove_container
end
private :remove_container
el = @messages[message.id]
return if el.message # we've seen it before
el = @messages[message.id]
return if el.message # we've seen it before
+ #puts "adding: #{message.id}, refs #{message.refs.inspect}"
+
el.message = message
oldroot = el.root
## link via references:
el.message = message
oldroot = el.root
## link via references:
- prev = nil
- message.refs.each do |ref_id|
+ (message.refs + [el.id]).inject(nil) do |prev, ref_id|
ref = @messages[ref_id]
link prev, ref if prev
ref = @messages[ref_id]
link prev, ref if prev
- link prev, el, true if prev
## link via in-reply-to:
message.replytos.each do |ref_id|
## link via in-reply-to:
message.replytos.each do |ref_id|
-
- ## new root. need to drop old one and put this one in its place
- if root != oldroot && oldroot.thread
- oldroot.thread.drop oldroot
- oldroot.thread = nil
- end
-
key =
if thread_by_subj?
Message.normalize_subj root.subj
key =
if thread_by_subj?
Message.normalize_subj root.subj