From 298f2778fbbbe1f59c1b9c8e3993f00b41c7b972 Mon Sep 17 00:00:00 2001 From: wmorgan Date: Fri, 8 Jun 2007 22:46:28 +0000 Subject: [PATCH] rework person management and have contact entries override anything else git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@441 5c8cc53c-5e98-4d25-b20a-d8db53a31250 --- lib/sup/contact.rb | 2 +- lib/sup/index.rb | 6 +-- lib/sup/message.rb | 12 +++--- lib/sup/person.rb | 99 +++++++++++++++++++++++++++++++--------------- 4 files changed, 77 insertions(+), 42 deletions(-) diff --git a/lib/sup/contact.rb b/lib/sup/contact.rb index badbc84..0706725 100644 --- a/lib/sup/contact.rb +++ b/lib/sup/contact.rb @@ -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 diff --git a/lib/sup/index.rb b/lib/sup/index.rb index 7d1e7a5..85db9c4 100644 --- a/lib/sup/index.rb +++ b/lib/sup/index.rb @@ -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 diff --git a/lib/sup/message.rb b/lib/sup/message.rb index 4f7b172..63c462a 100644 --- a/lib/sup/message.rb +++ b/lib/sup/message.rb @@ -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(/^$/, "") + @list_address = PersonManager.person_for header["list-post"].gsub(/^$/, "") else nil end diff --git a/lib/sup/person.rb b/lib/sup/person.rb index 19a3e97..9c2d687 100644 --- a/lib/sup/person.rb +++ b/lib/sup/person.rb @@ -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 -- 2.45.2