File: address.rb

package info (click to toggle)
ruby-mail 2.6.1%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 4,092 kB
  • ctags: 1,281
  • sloc: ruby: 43,919; makefile: 2
file content (270 lines) | stat: -rw-r--r-- 7,794 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# encoding: utf-8
module Mail
  class Address

    include Mail::Utilities
    
    # Mail::Address handles all email addresses in Mail.  It takes an email address string
    # and parses it, breaking it down into its component parts and allowing you to get the
    # address, comments, display name, name, local part, domain part and fully formatted
    # address.
    # 
    # Mail::Address requires a correctly formatted email address per RFC2822 or RFC822.  It
    # handles all obsolete versions including obsolete domain routing on the local part.
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.format       #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
    #  a.address      #=> 'mikel@test.lindsaar.net'
    #  a.display_name #=> 'Mikel Lindsaar'
    #  a.local        #=> 'mikel'
    #  a.domain       #=> 'test.lindsaar.net'
    #  a.comments     #=> ['My email address']
    #  a.to_s         #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
    def initialize(value = nil)
      @output_type = :decode
      if value.nil?
        @parsed = false
        @data = nil
        return
      else
        parse(value)
      end
    end
    
    # Returns the raw input of the passed in string, this is before it is passed
    # by the parser.
    def raw
      @data.raw
    end

    # Returns a correctly formatted address for the email going out.  If given
    # an incorrectly formatted address as input, Mail::Address will do its best
    # to format it correctly.  This includes quoting display names as needed and
    # putting the address in angle brackets etc.
    #
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
    def format
      parse unless @parsed
      if @data.nil?
        ''
      elsif display_name
        [quote_phrase(display_name), "<#{address}>", format_comments].compact.join(" ")
      elsif address
        [address, format_comments].compact.join(" ")
      else
        raw
      end
    end

    # Returns the address that is in the address itself.  That is, the 
    # local@domain string, without any angle brackets or the like.
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.address #=> 'mikel@test.lindsaar.net'
    def address
      parse unless @parsed
      domain ? "#{local}@#{domain}" : local
    end
    
    # Provides a way to assign an address to an already made Mail::Address object.
    # 
    #  a = Address.new
    #  a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
    #  a.address #=> 'mikel@test.lindsaar.net'
    def address=(value)
      parse(value)
    end
    
    # Returns the display name of the email address passed in.
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.display_name #=> 'Mikel Lindsaar'
    def display_name
      parse unless @parsed
      @display_name ||= get_display_name
      Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
    end
    
    # Provides a way to assign a display name to an already made Mail::Address object.
    # 
    #  a = Address.new
    #  a.address = 'mikel@test.lindsaar.net'
    #  a.display_name = 'Mikel Lindsaar'
    #  a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
    def display_name=( str )
      @display_name = str
    end

    # Returns the local part (the left hand side of the @ sign in the email address) of
    # the address
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.local #=> 'mikel'
    def local
      parse unless @parsed
      "#{@data.obs_domain_list}#{get_local.strip}" if get_local
    end

    # Returns the domain part (the right hand side of the @ sign in the email address) of
    # the address
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.domain #=> 'test.lindsaar.net'
    def domain
      parse unless @parsed
      strip_all_comments(get_domain) if get_domain
    end
    
    # Returns an array of comments that are in the email, or an empty array if there
    # are no comments
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.comments #=> ['My email address']
    def comments
      parse unless @parsed
      if get_comments.empty?
        nil
      else
        get_comments.map { |c| c.squeeze(" ") }
      end
    end
    
    # Sometimes an address will not have a display name, but might have the name
    # as a comment field after the address.  This returns that name if it exists.
    # 
    #  a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
    #  a.name #=> 'Mikel Lindsaar'
    def name
      parse unless @parsed
      get_name
    end
    
    # Returns the format of the address, or returns nothing
    # 
    #  a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
    #  a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
    def to_s
      parse unless @parsed
      format
    end
    
    # Shows the Address object basic details, including the Address
    #  a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
    #  a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
    def inspect
      parse unless @parsed
      "#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
    end
    
    def encoded
      @output_type = :encode
      format
    end
    
    def decoded
      @output_type = :decode
      format
    end

    private
    
    def parse(value = nil)
      @parsed = true

      case value
      when NilClass
        @data = nil
        nil
      when Mail::Parsers::AddressStruct
        @data = value
      when String
        @raw_text = value
        if value.blank?
          @data = nil
        else
          address_list = Mail::Parsers::AddressListsParser.new.parse(value)
          @data = address_list.addresses.first
        end
      end
    end
    
    def strip_all_comments(string)
      unless comments.blank?
        comments.each do |comment|
          string = string.gsub("(#{comment})", '')
        end
      end
      string.strip
    end

    def strip_domain_comments(value)
      unless comments.blank?
        comments.each do |comment|
          if @data.domain && @data.domain.include?("(#{comment})")
            value = value.gsub("(#{comment})", '')
          end
        end
      end
      value.to_s.strip
    end
    
    def get_display_name
      if @data.display_name
        str = strip_all_comments(@data.display_name.to_s)
      elsif @data.comments
        if @data.domain
          str = strip_domain_comments(format_comments)
        else
          str = nil
        end
      else
        nil
      end
      
      if str.blank?
        nil
      else
        str
      end
    end
    
    def get_name
      if display_name
        str = display_name
      else
        if comments
          comment_text = comments.join(' ').squeeze(" ")
          str = "(#{comment_text})"
        end
      end

      if str.blank?
        nil
      else
        unparen(str)
      end
    end
    
    def format_comments
      if comments
        comment_text = comments.map {|c| escape_paren(c) }.join(' ').squeeze(" ")
        @format_comments ||= "(#{comment_text})"
      else
        nil
      end
    end

    def get_local
      @data && @data.local
    end

    def get_domain
      @data && @data.domain
    end
    
    def get_comments
      @data && @data.comments
    end
  end
end