lib/sup/person.rb (3184B) - raw
1 module Redwood
2
3 class Person
4 attr_accessor :name, :email
5
6 def initialize name, email
7 raise ArgumentError, "email can't be nil" unless email
8
9 email.fix_encoding!
10
11 @name = if name
12 name.fix_encoding!
13 name = name.strip.gsub(/\s+/, " ")
14 name =~ /^(['"]\s*)(.*?)(\s*["'])$/ ? $2 : name
15 name.gsub('\\\\', '\\')
16 end
17
18 @email = email.strip.gsub(/\s+/, " ")
19 end
20
21 def to_s
22 if @name
23 "#@name <#@email>"
24 else
25 @email
26 end
27 end
28
29 # def == o; o && o.email == email; end
30 # alias :eql? :==
31
32 def shortname
33 case @name
34 when /\S+, (\S+)/
35 $1
36 when /(\S+) \S+/
37 $1
38 when nil
39 @email
40 else
41 @name
42 end
43 end
44
45 def mediumname; @name || @email; end
46
47 def longname
48 to_s
49 end
50
51 def full_address
52 Person.full_address @name, @email
53 end
54
55 ## when sorting addresses, sort by this
56 def sort_by_me
57 case @name
58 when /^(\S+), \S+/
59 $1
60 when /^\S+ \S+ (\S+)/
61 $1
62 when /^\S+ (\S+)/
63 $1
64 when nil
65 @email
66 else
67 @name
68 end.downcase
69 end
70
71 def eql? o; email.eql? o.email end
72 def hash; email.hash end
73
74
75 ## see comments in self.from_address
76 def indexable_content
77 [name, email, email.split(/@/).first].join(" ")
78 end
79
80 class << self
81
82 def full_address name, email
83 if name && email
84 if name =~ /[",@]/
85 "#{name.inspect} <#{email}>" # escape quotes
86 else
87 "#{name} <#{email}>"
88 end
89 else
90 email
91 end
92 end
93
94 ## return "canonical" person using contact manager or create one if
95 ## not found or contact manager not available
96 def from_name_and_email name, email
97 ContactManager.instantiated? && ContactManager.person_for(email) || Person.new(name, email)
98 end
99
100 def from_address s
101 return nil if s.nil?
102
103 ## try and parse an email address and name
104 name, email = case s
105 when /(.+?) ((\S+?)@\S+) \3/
106 ## ok, this first match cause is insane, but bear with me. email
107 ## addresses are stored in the to/from/etc fields of the index in a
108 ## weird format: "name address first-part-of-address", i.e. spaces
109 ## separating those three bits, and no <>'s. this is the output of
110 ## #indexable_content. here, we reverse-engineer that format to extract
111 ## a valid address.
112 ##
113 ## we store things this way to allow searches on a to/from/etc field to
114 ## match any of those parts. a more robust solution would be to store a
115 ## separate, non-indexed field with the proper headers. but this way we
116 ## save precious bits, and it's backwards-compatible with older indexes.
117 [$1, $2]
118 when /["'](.*?)["'] <(.*?)>/, /([^,]+) <(.*?)>/
119 a, b = $1, $2
120 [a.gsub('\"', '"'), b]
121 when /<((\S+?)@\S+?)>/
122 [$2, $1]
123 when /((\S+?)@\S+)/
124 [$2, $1]
125 else
126 [nil, s]
127 end
128
129 from_name_and_email name, email
130 end
131
132 def from_address_list ss
133 return [] if ss.nil?
134 ss.dup.split_on_commas.map { |s| self.from_address s }
135 end
136
137 end
138
139 end
140
141 end