]> git.cworth.org Git - sup/commitdiff
add the ability to joining threads forcefully to ThreadSet
authorWilliam Morgan <wmorgan-sup@masanjin.net>
Thu, 17 Jan 2008 00:44:43 +0000 (16:44 -0800)
committerWilliam Morgan <wmorgan-sup@masanjin.net>
Thu, 17 Jan 2008 00:44:43 +0000 (16:44 -0800)
ThreadSet#join_threads now takes any number of threads (which must be part
of the threadset) heuristically either picks one message to be the root
(if all messages but one have a "Re:" on the subject line), or creates
a fake root. It updates the message object and marks it dirty so that a
subsequent save will preserve the new structure.

lib/sup/message.rb
lib/sup/thread.rb

index c487ae35763902f6b847f789942e52c640d82fcf..651c839e76198a7b978e7aef1a4203e7562ef2fb 100644 (file)
@@ -55,6 +55,10 @@ class Message
     @encrypted = false
     @chunks = nil
 
+    ## we need to initialize this. see comments in parse_header as to
+    ## why.
+    @refs = []
+
     parse_header(opts[:header] || @source.load_header(@source_info))
   end
 
@@ -102,7 +106,13 @@ class Message
     @to = PersonManager.people_for header["to"]
     @cc = PersonManager.people_for header["cc"]
     @bcc = PersonManager.people_for header["bcc"]
-    @refs = (header["references"] || "").scan(/<(.+?)>/).map { |x| sanitize_message_id x.first }
+
+    ## before loading our full header from the source, we can actually
+    ## have some extra refs set by the UI. (this happens when the user
+    ## joins threads manually). so we will merge the current refs values
+    ## in here.
+    refs = (header["references"] || "").scan(/<(.+?)>/).map { |x| sanitize_message_id x.first }
+    @refs = (@refs + refs).uniq
     @replytos = (header["in-reply-to"] || "").scan(/<(.+?)>/).map { |x| sanitize_message_id x.first }
 
     @replyto = PersonManager.person_for header["reply-to"]
@@ -120,6 +130,11 @@ class Message
   end
   private :parse_header
 
+  def add_ref ref
+    @refs << ref
+    @dirty = true
+  end
+
   def snippet; @snippet || (chunks && @snippet); end
   def is_list_message?; !@list_address.nil?; end
   def is_draft?; @source.is_a? DraftLoader; end
index 3ade0244dacd357e48aaa52ceb880a25eaadce41..32002c4062cb0e9d7aabf317375cf22eafdeee65 100644 (file)
@@ -349,6 +349,32 @@ class ThreadSet
     t.each { |m, *o| add_message m }
   end
 
+  ## merges two threads together. both must be members of this threadset.
+  ## does its best, heuristically, to determine which is the parent.
+  def join_threads threads
+    return if threads.size < 2
+
+    containers = threads.map do |t|
+      c = @messages[t.first.id]
+      raise "not in threadset: #{t.first.id}" unless c && c.message
+      c
+    end
+
+    ## use subject headers heuristically
+    parent = containers.find { |c| !c.is_reply? }
+
+    ## no thread was rooted by a non-reply, so make a fake parent
+    parent ||= @messages["joining-ref-" + containers.map { |c| c.id }.join("-")]
+
+    containers.each do |c|
+      next if c == parent
+      c.message.add_ref parent.id
+      link parent, c
+    end
+
+    true
+  end
+
   def is_relevant? m
     m.refs.any? { |ref_id| @messages.member? ref_id }
   end