3
= Address handling class
7
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
9
# Permission is hereby granted, free of charge, to any person obtaining
10
# a copy of this software and associated documentation files (the
11
# "Software"), to deal in the Software without restriction, including
12
# without limitation the rights to use, copy, modify, merge, publish,
13
# distribute, sublicense, and/or sell copies of the Software, and to
14
# permit persons to whom the Software is furnished to do so, subject to
15
# the following conditions:
17
# The above copyright notice and this permission notice shall be
18
# included in all copies or substantial portions of the Software.
20
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
# Note: Originally licensed under LGPL v2+. Using MIT license for Rails
29
# with permission of Minero Aoki.
32
require 'tmail/encode'
33
require 'tmail/parser'
40
# Provides a complete handling library for email addresses. Can parse a string of an
41
# address directly or take in preformatted addresses themselves. Allows you to add
42
# and remove phrases from the front of the address and provides a compare function for
45
# == Parsing and Handling a Valid Address:
47
# Just pass the email address in as a string to Address.parse:
49
# email = TMail::Address.parse('Mikel Lindsaar <mikel@lindsaar.net>')
50
# #=> #<TMail::Address mikel@lindsaar.net>
52
# #=> "mikel@lindsaar.net"
57
# email.name # Aliased as phrase as well
58
# #=> "Mikel Lindsaar"
60
# == Detecting an Invalid Address
62
# If you want to check the syntactical validity of an email address, just pass it to
63
# Address.parse and catch any SyntaxError:
66
# TMail::Address.parse("mikel 2@@@@@ me .com")
67
# rescue TMail::SyntaxError
68
# puts("Invalid Email Address Detected")
70
# puts("Address is valid")
72
# #=> "Invalid Email Address Detected"
75
include TextUtils #:nodoc:
77
# Sometimes you need to parse an address, TMail can do it for you and provide you with
78
# a fairly robust method of detecting a valid address.
80
# Takes in a string, returns a TMail::Address object.
82
# Raises a TMail::SyntaxError on invalid email format
83
def Address.parse( str )
84
Parser.parse :ADDRESS, str
87
def address_group? #:nodoc:
91
# Address.new(local, domain)
95
# * local - Left of the at symbol
97
# * domain - Array of the domain split at the periods.
101
# Address.new("mikel", ["lindsaar", "net"])
102
# #=> "#<TMail::Address mikel@lindsaar.net>"
103
def initialize( local, domain )
106
raise SyntaxError, 'empty word in domain' if s.empty?
110
# This is to catch an unquoted "@" symbol in the local part of the
111
# address. Handles addresses like <"@"@me.com> and makes sure they
112
# stay like <"@"@me.com> (previously were becoming <@@me.com>)
113
if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/)
114
@local = "\"#{local.join}\""
124
# Provides the name or 'phrase' of the email address.
128
# email = TMail::Address.parse("Mikel Lindsaar <mikel@lindsaar.net>")
130
# #=> "Mikel Lindsaar"
135
# Setter method for the name or phrase of the email
139
# email = TMail::Address.parse("mikel@lindsaar.net")
142
# email.name = "Mikel Lindsaar"
144
# #=> "Mikel Lindsaar <mikel@me.com>"
147
@name = nil if str and str.empty?
155
# This is still here from RFC 822, and is now obsolete per RFC2822 Section 4.
157
# "When interpreting addresses, the route portion SHOULD be ignored."
159
# It is still here, so you can access it.
161
# Routes return the route portion at the front of the email address, if any.
164
# email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>")
165
# => #<TMail::Address Mikel@me.com>
167
# => "<@sa,@another:Mikel@me.com>"
169
# => ["sa", "another"]
175
"#<#{self.class} #{address()}>"
178
# Returns the local part of the email address
182
# email = TMail::Address.parse("mikel@lindsaar.net")
186
return nil unless @local
187
return '""' if @local.size == 1 and @local[0].empty?
188
# Check to see if it is an array before trying to map it
189
if @local.respond_to?(:map)
190
@local.map {|i| quote_atom(i) }.join('.')
196
# Returns the domain part of the email address
200
# email = TMail::Address.parse("mikel@lindsaar.net")
204
return nil unless @domain
208
# Returns the full specific address itself
212
# email = TMail::Address.parse("mikel@lindsaar.net")
214
# #=> "mikel@lindsaar.net"
227
# Provides == function to the email. Only checks the actual address
228
# and ignores the name/phrase component
232
# addr1 = TMail::Address.parse("My Address <mikel@lindsaar.net>")
233
# #=> "#<TMail::Address mikel@lindsaar.net>"
234
# addr2 = TMail::Address.parse("Another <mikel@lindsaar.net>")
235
# #=> "#<TMail::Address mikel@lindsaar.net>"
239
other.respond_to? :spec and self.spec == other.spec
244
# Provides a unique hash value for this record against the local and domain
245
# parts, ignores the name/phrase value
247
# email = TMail::Address.parse("mikel@lindsaar.net")
251
@local.hash ^ @domain.hash
254
# Duplicates a TMail::Address object returning the duplicate
256
# addr1 = TMail::Address.parse("mikel@lindsaar.net")
258
# addr1.id == addr2.id
261
obj = self.class.new(@local.dup, @domain.dup)
262
obj.name = @name.dup if @name
263
obj.routes.replace @routes
267
include StrategyInterface #:nodoc:
269
def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc:
271
strategy.meta '<>' # empty return-path
275
spec_p = (not @name and @routes.empty?)
277
strategy.phrase @name
280
tmp = spec_p ? '' : '<'
281
unless @routes.empty?
282
tmp << @routes.map {|i| '@' + i }.join(',') << ':'
285
tmp << '>' unless spec_p
301
def initialize( name, addrs )
309
other.respond_to? :to_a and @addresses == other.to_a
315
map {|i| i.hash }.hash
331
@addresses.each(&block)
341
@addresses.include? a
346
@addresses.each do |a|
347
if a.respond_to? :flatten
356
def each_address( &block )
370
include StrategyInterface
372
def accept( strategy, dummy1 = nil, dummy2 = nil )
373
strategy.phrase @name
381
strategy.puts_meta ','