]> git.notmuchmail.org Git - sup/commitdiff
rework person management and have contact entries override anything else
authorwmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Fri, 8 Jun 2007 22:46:28 +0000 (22:46 +0000)
committerwmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Fri, 8 Jun 2007 22:46:28 +0000 (22:46 +0000)
git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@441 5c8cc53c-5e98-4d25-b20a-d8db53a31250

lib/sup/contact.rb
lib/sup/index.rb
lib/sup/message.rb
lib/sup/person.rb

index badbc8426e447b02f2c18671c2c44ae86c8ac0a5..07067258a7e9cb92f274e944bb1b397c63c33fe2 100644 (file)
@@ -12,7 +12,7 @@ class ContactManager
       IO.foreach(fn) do |l|
         l =~ /^(\S+): (.*)$/ or raise "can't parse #{fn} line #{l.inspect}"
         aalias, addr = $1, $2
-        p = Person.for addr
+        p = PersonManager.person_for addr, :definitive => true
         @p2a[p] = aalias
         @a2p[aalias] = p
       end
index 7d1e7a5fc9242e32e971802ce681d2fc85aca2a8..85db9c4e9934462b82ee8dab43fa517b3db3971e 100644 (file)
@@ -330,11 +330,9 @@ EOS
       t = @index[docid][:to]
 
       if AccountManager.is_account_email? f
-        t.split(" ").each { |e| #Redwood::log "adding #{e} because there's a message to him from account email #{f}"; 
-          contacts[Person.for(e)] = true }
+        t.split(" ").each { |e| contacts[PersonManager.person_for(e)] = true }
       else
-        #Redwood::log "adding from #{f} because there's a message from him to #{t}"
-        contacts[Person.for(f)] = true
+        contacts[PersonManager.person_for(f)] = true
       end
     end
 
index 4f7b172c6b9139109f01d557f245be504f83203f..63c462a8ba71c2b0f2c20789aa6050e4da3e18ae 100644 (file)
@@ -119,17 +119,17 @@ class Message
     end
 
     @subj = header.member?("subject") ? header["subject"].gsub(/\s+/, " ").gsub(/\s+$/, "") : DEFAULT_SUBJECT
-    @from = Person.for header["from"]
-    @to = Person.for_several header["to"]
-    @cc = Person.for_several header["cc"]
-    @bcc = Person.for_several header["bcc"]
+    @from = PersonManager.person_for header["from"]
+    @to = PersonManager.people_for header["to"]
+    @cc = PersonManager.people_for header["cc"]
+    @bcc = PersonManager.people_for header["bcc"]
     @id = header["message-id"]
     @refs = (header["references"] || "").gsub(/[<>]/, "").split(/\s+/).flatten
     @replytos = (header["in-reply-to"] || "").scan(/<(.*?)>/).flatten
-    @replyto = Person.for header["reply-to"]
+    @replyto = PersonManager.person_for header["reply-to"]
     @list_address =
       if header["list-post"]
-        @list_address = Person.for header["list-post"].gsub(/^<mailto:|>$/, "")
+        @list_address = PersonManager.person_for header["list-post"].gsub(/^<mailto:|>$/, "")
       else
         nil
       end
index 19a3e97eacbf9105bc6ead6ff9d178df1abd299a..9c2d687eebceb7216a732b997ac18def45a6d928 100644 (file)
@@ -5,42 +5,85 @@ class PersonManager
 
   def initialize fn
     @fn = fn
-    @names = {}
-    IO.readlines(fn).map { |l| l =~ /^(.*)?:\s+(\d+)\s+(.*)$/ && @names[$1] = [$2.to_i, $3] } if File.exists? fn
+    @@people = {}
+
+    ## read in stored people
+    IO.readlines(fn).map do |l|
+      l =~ /^(.*)?:\s+(\d+)\s+(.*)$/ or raise "can't parse: #{l}"
+      email, time, name = $1, $2, $3
+      @@people[email] = Person.new name, email, time, false
+    end if File.exists? fn
+
     self.class.i_am_the_instance self
   end
 
-  def name_for email; @names.member?(email) ? @names[email][1] : nil; end
-  def register email, name
-    return unless name
-
-    name = name.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").gsub(/^['"]|['"]$/, "")
+  def save
+    File.open(@fn, "w") do |f|
+      @@people.each do |email, p|
+        f.puts "#{p.email}: #{p.timestamp} #{p.name}"
+      end
+    end
+  end
 
-    ## all else being equal, prefer longer names, unless the prior name
-    ## doesn't contain any capitalization
-    oldcount, oldname = @names[email]
-    @names[email] = [0, name] if oldname.nil? || oldname.length < name.length || (oldname !~ /[A-Z]/ && name =~ /[A-Z]/)
-    @names[email][0] = Time.now.to_i
+  def self.people_for s, opts={}
+    return [] if s.nil?
+    s.split_on_commas.map { |ss| self.person_for ss, opts }
   end
 
-  def save; File.open(@fn, "w") { |f| @names.each { |email, (time, name)| f.puts "#{email}: #{time} #{name}" unless email =~ /no\-?reply/ } }; end
-end
+  def self.person_for s, opts={}
+    p = Person.from_address(s) or return nil
+    p.definitive = true if opts[:definitive]
+    oldp = @@people[p.email]
+
+    if oldp.nil? || p.better_than?(oldp)
+      @@people[p.email] = p
+    end
 
-class Person
-  @@email_map = {}
+    @@people[p.email].touch!
+    @@people[p.email]
+  end
+end
 
-  attr_accessor :name, :email
+## don't create these by hand. rather, go through personmanager, to
+## ensure uniqueness and overriding.
+class Person 
+  attr_accessor :name, :email, :timestamp
+  bool_accessor :definitive
 
-  def initialize name, email
+  def initialize name, email, timestamp=0, definitive=false
     raise ArgumentError, "email can't be nil" unless email
+    
+    if name
+      @name = name.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ")
+      if @name =~ /^(['"]\s*)(.*?)(\s*["'])$/
+        @name = $2
+      end
+    end
+
     @email = email.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").downcase
-    PersonManager.register @email, name
-    @name = PersonManager.name_for @email
+    @definitive = definitive
+    @timestamp = timestamp
+  end
+
+  ## heuristic: whether the name attached to this email is "real", i.e. 
+  ## we should bother to store it.
+  def generic?
+    @email =~ /no\-?reply/
+  end
+
+  def better_than? o
+    return false if o.definitive? || generic?
+    return true if definitive?
+    o.name.nil? || (name && name.length > o.name.length && name =~ /[a-z]/)
   end
 
-  def == o; o && o.email == email; end
-  alias :eql? :==
-  def hash; [name, email].hash; end
+  def to_s; "#@name <#@email>" end
+
+  def touch!; @timestamp = Time.now.to_i end
+
+#   def == o; o && o.email == email; end
+#   alias :eql? :==
+#   def hash; [name, email].hash; end
 
   def shortname
     case @name
@@ -93,7 +136,7 @@ class Person
     end.downcase
   end
 
-  def self.for s
+  def self.from_address s
     return nil if s.nil?
 
     ## try and parse an email address and name
@@ -110,13 +153,7 @@ class Person
         [nil, s]
       end
 
-    @@email_map[email] ||= Person.new name, email
-  end
-
-  def self.for_several s
-    return [] if s.nil?
-
-    s.split_on_commas.map { |ss| self.for ss }
+    Person.new name, email
   end
 end