mail 2.4.4 → 2.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +156 -0
- data/CONTRIBUTING.md +21 -6
- data/Dependencies.txt +0 -1
- data/Gemfile +10 -21
- data/MIT-LICENSE +20 -0
- data/README.md +52 -32
- data/Rakefile +11 -22
- data/lib/mail/attachments_list.rb +2 -2
- data/lib/mail/body.rb +33 -9
- data/lib/mail/check_delivery_params.rb +20 -0
- data/lib/mail/configuration.rb +1 -1
- data/lib/mail/{patterns.rb → constants.rb} +26 -6
- data/lib/mail/core_extensions/nil.rb +4 -2
- data/lib/mail/core_extensions/object.rb +8 -8
- data/lib/mail/core_extensions/smtp.rb +12 -13
- data/lib/mail/core_extensions/string.rb +19 -6
- data/lib/mail/elements/address.rb +82 -141
- data/lib/mail/elements/address_list.rb +9 -42
- data/lib/mail/elements/content_disposition_element.rb +3 -7
- data/lib/mail/elements/content_location_element.rb +2 -6
- data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
- data/lib/mail/elements/content_type_element.rb +4 -8
- data/lib/mail/elements/date_time_element.rb +3 -7
- data/lib/mail/elements/envelope_from_element.rb +18 -13
- data/lib/mail/elements/message_ids_element.rb +1 -6
- data/lib/mail/elements/mime_version_element.rb +3 -7
- data/lib/mail/elements/phrase_list.rb +2 -7
- data/lib/mail/elements/received_element.rb +3 -7
- data/lib/mail/elements.rb +12 -12
- data/lib/mail/encodings/quoted_printable.rb +4 -3
- data/lib/mail/encodings/unix_to_unix.rb +17 -0
- data/lib/mail/encodings.rb +53 -38
- data/lib/mail/envelope.rb +0 -5
- data/lib/mail/field.rb +131 -118
- data/lib/mail/field_list.rb +18 -18
- data/lib/mail/fields/bcc_field.rb +2 -2
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +1 -1
- data/lib/mail/fields/common/common_address.rb +32 -22
- data/lib/mail/fields/common/common_date.rb +0 -7
- data/lib/mail/fields/common/common_field.rb +10 -3
- data/lib/mail/fields/common/common_message_id.rb +9 -5
- data/lib/mail/fields/common/parameter_hash.rb +3 -3
- data/lib/mail/fields/content_disposition_field.rb +1 -0
- data/lib/mail/fields/content_id_field.rb +1 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +2 -8
- data/lib/mail/fields/content_type_field.rb +5 -2
- data/lib/mail/fields/date_field.rb +14 -14
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/keywords_field.rb +1 -1
- data/lib/mail/fields/message_id_field.rb +2 -3
- data/lib/mail/fields/references_field.rb +2 -1
- data/lib/mail/fields/reply_to_field.rb +2 -2
- data/lib/mail/fields/resent_bcc_field.rb +2 -2
- data/lib/mail/fields/resent_cc_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_sender_field.rb +3 -3
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +8 -8
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +44 -31
- data/lib/mail/fields.rb +32 -32
- data/lib/mail/header.rb +47 -37
- data/lib/mail/mail.rb +15 -1
- data/lib/mail/matchers/has_sent_mail.rb +36 -3
- data/lib/mail/message.rb +164 -57
- data/lib/mail/multibyte/chars.rb +4 -4
- data/lib/mail/multibyte/unicode.rb +9 -1
- data/lib/mail/network/delivery_methods/exim.rb +2 -3
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +35 -8
- data/lib/mail/network/delivery_methods/smtp.rb +34 -45
- data/lib/mail/network/delivery_methods/smtp_connection.rb +9 -22
- data/lib/mail/network/delivery_methods/test_mailer.rb +6 -2
- data/lib/mail/network/retriever_methods/imap.rb +32 -19
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +11 -15
- data/lib/mail/network.rb +9 -9
- data/lib/mail/parsers/address_lists_parser.rb +132 -0
- data/lib/mail/parsers/content_disposition_parser.rb +67 -0
- data/lib/mail/parsers/content_location_parser.rb +35 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
- data/lib/mail/parsers/content_type_parser.rb +66 -0
- data/lib/mail/parsers/date_time_parser.rb +36 -0
- data/lib/mail/parsers/envelope_from_parser.rb +45 -0
- data/lib/mail/parsers/message_ids_parser.rb +39 -0
- data/lib/mail/parsers/mime_version_parser.rb +41 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
- data/lib/mail/parsers/ragel/common.rl +185 -0
- data/lib/mail/parsers/ragel/date_time.rl +30 -0
- data/lib/mail/parsers/ragel/parser_info.rb +61 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2149 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
- data/lib/mail/parsers/ragel/ruby.rb +40 -0
- data/lib/mail/parsers/ragel.rb +17 -0
- data/lib/mail/parsers/received_parser.rb +47 -0
- data/lib/mail/parsers.rb +26 -0
- data/lib/mail/part.rb +6 -2
- data/lib/mail/parts_list.rb +5 -3
- data/lib/mail/utilities.rb +70 -60
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +7 -15
- data/lib/mail/version_specific/ruby_1_8.rb +25 -4
- data/lib/mail/version_specific/ruby_1_9.rb +110 -30
- data/lib/mail.rb +20 -19
- metadata +129 -73
- data/Gemfile.lock +0 -36
- data/lib/VERSION +0 -4
- data/lib/mail/core_extensions/shell_escape.rb +0 -56
- data/lib/mail/parsers/address_lists.rb +0 -64
- data/lib/mail/parsers/address_lists.treetop +0 -19
- data/lib/mail/parsers/content_disposition.rb +0 -535
- data/lib/mail/parsers/content_disposition.treetop +0 -46
- data/lib/mail/parsers/content_location.rb +0 -139
- data/lib/mail/parsers/content_location.treetop +0 -20
- data/lib/mail/parsers/content_transfer_encoding.rb +0 -162
- data/lib/mail/parsers/content_transfer_encoding.treetop +0 -20
- data/lib/mail/parsers/content_type.rb +0 -967
- data/lib/mail/parsers/content_type.treetop +0 -68
- data/lib/mail/parsers/date_time.rb +0 -114
- data/lib/mail/parsers/date_time.treetop +0 -11
- data/lib/mail/parsers/envelope_from.rb +0 -194
- data/lib/mail/parsers/envelope_from.treetop +0 -32
- data/lib/mail/parsers/message_ids.rb +0 -45
- data/lib/mail/parsers/message_ids.treetop +0 -15
- data/lib/mail/parsers/mime_version.rb +0 -144
- data/lib/mail/parsers/mime_version.treetop +0 -19
- data/lib/mail/parsers/phrase_lists.rb +0 -45
- data/lib/mail/parsers/phrase_lists.treetop +0 -15
- data/lib/mail/parsers/received.rb +0 -71
- data/lib/mail/parsers/received.treetop +0 -11
- data/lib/mail/parsers/rfc2045.rb +0 -464
- data/lib/mail/parsers/rfc2045.treetop +0 -36
- data/lib/mail/parsers/rfc2822.rb +0 -5341
- data/lib/mail/parsers/rfc2822.treetop +0 -410
- data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
- data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
- data/lib/tasks/corpus.rake +0 -125
- data/lib/tasks/treetop.rake +0 -10
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
# encoding: us-ascii
|
|
2
2
|
module Mail
|
|
3
|
-
module
|
|
3
|
+
module Constants
|
|
4
4
|
white_space = %Q|\x9\x20|
|
|
5
5
|
text = %Q|\x1-\x8\xB\xC\xE-\x7f|
|
|
6
6
|
field_name = %Q|\x21-\x39\x3b-\x7e|
|
|
7
7
|
qp_safe = %Q|\x20-\x3c\x3e-\x7e|
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
aspecial = %Q|()<>[]:;@\\,."| # RFC5322
|
|
10
10
|
tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045
|
|
11
|
-
lwsp = %Q| \t\r\n|
|
|
12
11
|
sp = %Q| |
|
|
13
12
|
control = %Q|\x00-\x1f\x7f-\xff|
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
if control.respond_to?(:force_encoding)
|
|
16
15
|
control = control.force_encoding(Encoding::BINARY)
|
|
17
16
|
end
|
|
18
|
-
|
|
17
|
+
|
|
19
18
|
CRLF = /\r\n/
|
|
20
19
|
WSP = /[#{white_space}]/
|
|
21
20
|
FWS = /#{CRLF}#{WSP}*/
|
|
22
21
|
TEXT = /[#{text}]/ # + obs-text
|
|
23
22
|
FIELD_NAME = /[#{field_name}]+/
|
|
24
|
-
|
|
23
|
+
FIELD_PREFIX = /\A(#{FIELD_NAME})/
|
|
24
|
+
FIELD_BODY = /.+/m
|
|
25
25
|
FIELD_LINE = /^[#{field_name}]+:\s*.+$/
|
|
26
|
+
FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
|
|
26
27
|
HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
|
|
28
|
+
HEADER_SPLIT = /#{CRLF}(?!#{WSP})/
|
|
27
29
|
|
|
28
30
|
QP_UNSAFE = /[^#{qp_safe}]/
|
|
29
31
|
QP_SAFE = /[#{qp_safe}]/
|
|
@@ -31,5 +33,23 @@ module Mail
|
|
|
31
33
|
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
|
|
32
34
|
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
|
33
35
|
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
|
|
36
|
+
ENCODED_VALUE = /\=\?[^?]+\?([QB])\?[^?]*?\?\=/mi
|
|
37
|
+
|
|
38
|
+
EMPTY = ''
|
|
39
|
+
SPACE = ' '
|
|
40
|
+
UNDERSCORE = '_'
|
|
41
|
+
HYPHEN = '-'
|
|
42
|
+
COLON = ':'
|
|
43
|
+
ASTERISK = '*'
|
|
44
|
+
CR = "\r"
|
|
45
|
+
LF = "\n"
|
|
46
|
+
CR_ENCODED = "=0D"
|
|
47
|
+
LF_ENCODED = "=0A"
|
|
48
|
+
CAPITAL_M = 'M'
|
|
49
|
+
EQUAL_LF = "=\n"
|
|
50
|
+
NULL_SENDER = '<>'
|
|
51
|
+
|
|
52
|
+
Q_VALUES = ['Q','q']
|
|
53
|
+
B_VALUES = ['B','b']
|
|
34
54
|
end
|
|
35
55
|
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
unless Object.method_defined? :blank?
|
|
4
|
+
class Object
|
|
5
|
+
def blank?
|
|
6
|
+
if respond_to?(:empty?)
|
|
7
|
+
empty?
|
|
8
|
+
else
|
|
9
|
+
!self
|
|
10
|
+
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -5,21 +5,20 @@ module Net
|
|
|
5
5
|
# http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294
|
|
6
6
|
#
|
|
7
7
|
# Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
|
|
8
|
-
|
|
8
|
+
begin
|
|
9
|
+
alias_method :original_tlsconnect, :tlsconnect
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
def tlsconnect(s)
|
|
12
|
+
verified = false
|
|
13
|
+
begin
|
|
14
|
+
original_tlsconnect(s).tap { verified = true }
|
|
15
|
+
ensure
|
|
16
|
+
unless verified
|
|
17
|
+
s.close rescue nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
18
20
|
end
|
|
19
|
-
|
|
20
|
-
s
|
|
21
|
-
ensure
|
|
22
|
-
s.close unless verified
|
|
21
|
+
rescue NameError
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
end
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
class String #:nodoc:
|
|
3
|
+
|
|
4
|
+
CRLF = "\r\n"
|
|
5
|
+
LF = "\n"
|
|
6
|
+
|
|
7
|
+
if RUBY_VERSION >= '1.9'
|
|
8
|
+
# This 1.9 only regex can save a reasonable amount of time (~20%)
|
|
9
|
+
# by not matching "\r\n" so the string is returned unchanged in
|
|
10
|
+
# the common case.
|
|
11
|
+
CRLF_REGEX = Regexp.new("(?<!\r)\n|\r(?!\n)")
|
|
12
|
+
else
|
|
13
|
+
CRLF_REGEX = /\n|\r\n|\r/
|
|
14
|
+
end
|
|
15
|
+
|
|
3
16
|
def to_crlf
|
|
4
|
-
to_str.gsub(
|
|
17
|
+
to_str.gsub(CRLF_REGEX, CRLF)
|
|
5
18
|
end
|
|
6
19
|
|
|
7
20
|
def to_lf
|
|
8
|
-
to_str.gsub(/\
|
|
21
|
+
to_str.gsub(/\r\n|\r/, LF)
|
|
9
22
|
end
|
|
10
23
|
|
|
11
24
|
unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
|
|
@@ -15,12 +28,12 @@ class String #:nodoc:
|
|
|
15
28
|
end
|
|
16
29
|
|
|
17
30
|
unless method_defined?(:ascii_only?)
|
|
18
|
-
#
|
|
19
|
-
# returns true or false
|
|
20
|
-
US_ASCII_REGEXP = %Q{\x00-\x7f}
|
|
31
|
+
# Backport from Ruby 1.9 checks for non-us-ascii characters.
|
|
21
32
|
def ascii_only?
|
|
22
|
-
|
|
33
|
+
self !~ MATCH_NON_US_ASCII
|
|
23
34
|
end
|
|
35
|
+
|
|
36
|
+
MATCH_NON_US_ASCII = /[^\x00-\x7f]/
|
|
24
37
|
end
|
|
25
38
|
|
|
26
39
|
def not_ascii_only?
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Mail
|
|
3
3
|
class Address
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
include Mail::Utilities
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
|
8
|
-
# and parses it, breaking it down into
|
|
8
|
+
# and parses it, breaking it down into its component parts and allowing you to get the
|
|
9
9
|
# address, comments, display name, name, local part, domain part and fully formatted
|
|
10
10
|
# address.
|
|
11
|
-
#
|
|
11
|
+
#
|
|
12
12
|
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
|
13
13
|
# handles all obsolete versions including obsolete domain routing on the local part.
|
|
14
|
-
#
|
|
14
|
+
#
|
|
15
15
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
16
16
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
17
17
|
# a.address #=> 'mikel@test.lindsaar.net'
|
|
@@ -21,26 +21,23 @@ module Mail
|
|
|
21
21
|
# a.comments #=> ['My email address']
|
|
22
22
|
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
23
23
|
def initialize(value = nil)
|
|
24
|
-
@output_type =
|
|
25
|
-
|
|
26
|
-
@raw_text = value
|
|
27
|
-
case
|
|
28
|
-
when value.nil?
|
|
24
|
+
@output_type = :decode
|
|
25
|
+
if value.nil?
|
|
29
26
|
@parsed = false
|
|
30
|
-
|
|
27
|
+
@data = nil
|
|
31
28
|
else
|
|
32
29
|
parse(value)
|
|
33
30
|
end
|
|
34
31
|
end
|
|
35
|
-
|
|
36
|
-
# Returns the raw
|
|
32
|
+
|
|
33
|
+
# Returns the raw input of the passed in string, this is before it is passed
|
|
37
34
|
# by the parser.
|
|
38
35
|
def raw
|
|
39
|
-
@
|
|
36
|
+
@data.raw
|
|
40
37
|
end
|
|
41
38
|
|
|
42
39
|
# Returns a correctly formatted address for the email going out. If given
|
|
43
|
-
# an incorrectly formatted address as input, Mail::Address will do
|
|
40
|
+
# an incorrectly formatted address as input, Mail::Address will do its best
|
|
44
41
|
# to format it correctly. This includes quoting display names as needed and
|
|
45
42
|
# putting the address in angle brackets etc.
|
|
46
43
|
#
|
|
@@ -48,37 +45,38 @@ module Mail
|
|
|
48
45
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
49
46
|
def format
|
|
50
47
|
parse unless @parsed
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
if @data.nil?
|
|
49
|
+
EMPTY
|
|
50
|
+
elsif display_name
|
|
51
|
+
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(SPACE)
|
|
52
|
+
elsif address
|
|
53
|
+
[address, format_comments].compact.join(SPACE)
|
|
56
54
|
else
|
|
57
|
-
|
|
55
|
+
raw
|
|
58
56
|
end
|
|
59
57
|
end
|
|
60
58
|
|
|
61
|
-
# Returns the address that is in the address itself. That is, the
|
|
59
|
+
# Returns the address that is in the address itself. That is, the
|
|
62
60
|
# local@domain string, without any angle brackets or the like.
|
|
63
|
-
#
|
|
61
|
+
#
|
|
64
62
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
65
63
|
# a.address #=> 'mikel@test.lindsaar.net'
|
|
66
64
|
def address
|
|
67
65
|
parse unless @parsed
|
|
68
66
|
domain ? "#{local}@#{domain}" : local
|
|
69
67
|
end
|
|
70
|
-
|
|
68
|
+
|
|
71
69
|
# Provides a way to assign an address to an already made Mail::Address object.
|
|
72
|
-
#
|
|
70
|
+
#
|
|
73
71
|
# a = Address.new
|
|
74
72
|
# a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
|
|
75
73
|
# a.address #=> 'mikel@test.lindsaar.net'
|
|
76
74
|
def address=(value)
|
|
77
75
|
parse(value)
|
|
78
76
|
end
|
|
79
|
-
|
|
77
|
+
|
|
80
78
|
# Returns the display name of the email address passed in.
|
|
81
|
-
#
|
|
79
|
+
#
|
|
82
80
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
83
81
|
# a.display_name #=> 'Mikel Lindsaar'
|
|
84
82
|
def display_name
|
|
@@ -86,9 +84,9 @@ module Mail
|
|
|
86
84
|
@display_name ||= get_display_name
|
|
87
85
|
Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
|
|
88
86
|
end
|
|
89
|
-
|
|
87
|
+
|
|
90
88
|
# Provides a way to assign a display name to an already made Mail::Address object.
|
|
91
|
-
#
|
|
89
|
+
#
|
|
92
90
|
# a = Address.new
|
|
93
91
|
# a.address = 'mikel@test.lindsaar.net'
|
|
94
92
|
# a.display_name = 'Mikel Lindsaar'
|
|
@@ -99,57 +97,53 @@ module Mail
|
|
|
99
97
|
|
|
100
98
|
# Returns the local part (the left hand side of the @ sign in the email address) of
|
|
101
99
|
# the address
|
|
102
|
-
#
|
|
100
|
+
#
|
|
103
101
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
104
102
|
# a.local #=> 'mikel'
|
|
105
103
|
def local
|
|
106
104
|
parse unless @parsed
|
|
107
|
-
"#{obs_domain_list}#{get_local.strip}" if get_local
|
|
105
|
+
"#{@data.obs_domain_list}#{get_local.strip}" if get_local
|
|
108
106
|
end
|
|
109
107
|
|
|
110
108
|
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
|
111
109
|
# the address
|
|
112
|
-
#
|
|
110
|
+
#
|
|
113
111
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
114
112
|
# a.domain #=> 'test.lindsaar.net'
|
|
115
113
|
def domain
|
|
116
114
|
parse unless @parsed
|
|
117
115
|
strip_all_comments(get_domain) if get_domain
|
|
118
116
|
end
|
|
119
|
-
|
|
117
|
+
|
|
120
118
|
# Returns an array of comments that are in the email, or an empty array if there
|
|
121
119
|
# are no comments
|
|
122
|
-
#
|
|
120
|
+
#
|
|
123
121
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
124
122
|
# a.comments #=> ['My email address']
|
|
125
123
|
def comments
|
|
126
124
|
parse unless @parsed
|
|
127
|
-
|
|
128
|
-
nil
|
|
129
|
-
else
|
|
130
|
-
get_comments.map { |c| c.squeeze(" ") }
|
|
131
|
-
end
|
|
125
|
+
get_comments.map { |c| c.squeeze(SPACE) } unless get_comments.empty?
|
|
132
126
|
end
|
|
133
|
-
|
|
127
|
+
|
|
134
128
|
# Sometimes an address will not have a display name, but might have the name
|
|
135
129
|
# as a comment field after the address. This returns that name if it exists.
|
|
136
|
-
#
|
|
130
|
+
#
|
|
137
131
|
# a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
|
|
138
132
|
# a.name #=> 'Mikel Lindsaar'
|
|
139
133
|
def name
|
|
140
134
|
parse unless @parsed
|
|
141
135
|
get_name
|
|
142
136
|
end
|
|
143
|
-
|
|
137
|
+
|
|
144
138
|
# Returns the format of the address, or returns nothing
|
|
145
|
-
#
|
|
139
|
+
#
|
|
146
140
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
147
141
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
148
142
|
def to_s
|
|
149
143
|
parse unless @parsed
|
|
150
144
|
format
|
|
151
145
|
end
|
|
152
|
-
|
|
146
|
+
|
|
153
147
|
# Shows the Address object basic details, including the Address
|
|
154
148
|
# a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
|
|
155
149
|
# a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
|
|
@@ -157,48 +151,42 @@ module Mail
|
|
|
157
151
|
parse unless @parsed
|
|
158
152
|
"#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
|
|
159
153
|
end
|
|
160
|
-
|
|
154
|
+
|
|
161
155
|
def encoded
|
|
162
156
|
@output_type = :encode
|
|
163
157
|
format
|
|
164
158
|
end
|
|
165
|
-
|
|
159
|
+
|
|
166
160
|
def decoded
|
|
167
161
|
@output_type = :decode
|
|
168
162
|
format
|
|
169
163
|
end
|
|
170
164
|
|
|
165
|
+
def group
|
|
166
|
+
@data && @data.group
|
|
167
|
+
end
|
|
168
|
+
|
|
171
169
|
private
|
|
172
|
-
|
|
170
|
+
|
|
173
171
|
def parse(value = nil)
|
|
174
172
|
@parsed = true
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
when
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def get_domain
|
|
187
|
-
if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
|
|
188
|
-
@domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
|
|
189
|
-
elsif tree.respond_to?(:domain)
|
|
190
|
-
@domain_text ||= tree.domain.text_value.strip
|
|
191
|
-
elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
|
|
192
|
-
tree.addr_spec.domain.text_value.strip
|
|
193
|
-
else
|
|
194
|
-
nil
|
|
173
|
+
@data = nil
|
|
174
|
+
|
|
175
|
+
case value
|
|
176
|
+
when Mail::Parsers::AddressStruct
|
|
177
|
+
@data = value
|
|
178
|
+
when String
|
|
179
|
+
unless value.blank?
|
|
180
|
+
address_list = Mail::Parsers::AddressListsParser.new.parse(value)
|
|
181
|
+
@data = address_list.addresses.first
|
|
182
|
+
end
|
|
195
183
|
end
|
|
196
184
|
end
|
|
197
185
|
|
|
198
186
|
def strip_all_comments(string)
|
|
199
187
|
unless comments.blank?
|
|
200
188
|
comments.each do |comment|
|
|
201
|
-
string = string.gsub("(#{comment})",
|
|
189
|
+
string = string.gsub("(#{comment})", EMPTY)
|
|
202
190
|
end
|
|
203
191
|
end
|
|
204
192
|
string.strip
|
|
@@ -207,100 +195,53 @@ module Mail
|
|
|
207
195
|
def strip_domain_comments(value)
|
|
208
196
|
unless comments.blank?
|
|
209
197
|
comments.each do |comment|
|
|
210
|
-
if
|
|
211
|
-
value = value.gsub("(#{comment})",
|
|
198
|
+
if @data.domain && @data.domain.include?("(#{comment})")
|
|
199
|
+
value = value.gsub("(#{comment})", EMPTY)
|
|
212
200
|
end
|
|
213
201
|
end
|
|
214
202
|
end
|
|
215
203
|
value.to_s.strip
|
|
216
204
|
end
|
|
217
|
-
|
|
218
|
-
def get_comments
|
|
219
|
-
if tree.respond_to?(:comments)
|
|
220
|
-
@comments = tree.comments.map { |c| unparen(c.text_value.to_str) }
|
|
221
|
-
else
|
|
222
|
-
@comments = []
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
|
|
205
|
+
|
|
226
206
|
def get_display_name
|
|
227
|
-
if
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if domain
|
|
232
|
-
str = strip_domain_comments(format_comments)
|
|
233
|
-
else
|
|
234
|
-
str = nil
|
|
235
|
-
end
|
|
236
|
-
else
|
|
237
|
-
nil
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
if str.blank?
|
|
241
|
-
nil
|
|
242
|
-
else
|
|
243
|
-
str
|
|
207
|
+
if @data.display_name
|
|
208
|
+
str = strip_all_comments(@data.display_name.to_s)
|
|
209
|
+
elsif @data.comments && @data.domain
|
|
210
|
+
str = strip_domain_comments(format_comments)
|
|
244
211
|
end
|
|
212
|
+
|
|
213
|
+
str unless str.blank?
|
|
245
214
|
end
|
|
246
|
-
|
|
215
|
+
|
|
247
216
|
def get_name
|
|
248
217
|
if display_name
|
|
249
218
|
str = display_name
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
comment_text = comments.join(' ').squeeze(" ")
|
|
253
|
-
str = "(#{comment_text})"
|
|
254
|
-
end
|
|
219
|
+
elsif comments
|
|
220
|
+
str = "(#{comments.join(SPACE).squeeze(SPACE)})"
|
|
255
221
|
end
|
|
256
222
|
|
|
257
|
-
|
|
258
|
-
nil
|
|
259
|
-
else
|
|
260
|
-
unparen(str)
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
# Provides access to the Treetop parse tree for this address
|
|
265
|
-
def tree
|
|
266
|
-
@tree
|
|
223
|
+
unparen(str) unless str.blank?
|
|
267
224
|
end
|
|
268
|
-
|
|
269
|
-
def tree=(value)
|
|
270
|
-
@tree = value
|
|
271
|
-
end
|
|
272
|
-
|
|
225
|
+
|
|
273
226
|
def format_comments
|
|
274
227
|
if comments
|
|
275
|
-
comment_text = comments.map {|c| escape_paren(c) }.join(
|
|
228
|
+
comment_text = comments.map {|c| escape_paren(c) }.join(SPACE).squeeze(SPACE)
|
|
276
229
|
@format_comments ||= "(#{comment_text})"
|
|
277
230
|
else
|
|
278
231
|
nil
|
|
279
232
|
end
|
|
280
233
|
end
|
|
281
|
-
|
|
282
|
-
def obs_domain_list
|
|
283
|
-
if tree.respond_to?(:angle_addr)
|
|
284
|
-
obs = tree.angle_addr.elements.select { |e| e.respond_to?(:obs_domain_list) }
|
|
285
|
-
!obs.empty? ? obs.first.text_value : nil
|
|
286
|
-
else
|
|
287
|
-
nil
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
234
|
+
|
|
291
235
|
def get_local
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
end
|
|
236
|
+
@data && @data.local
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def get_domain
|
|
240
|
+
@data && @data.domain
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def get_comments
|
|
244
|
+
@data && @data.comments
|
|
302
245
|
end
|
|
303
|
-
|
|
304
|
-
|
|
305
246
|
end
|
|
306
|
-
end
|
|
247
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Mail
|
|
3
3
|
class AddressList # :nodoc:
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
# Mail::AddressList is the class that parses To, From and other address fields from
|
|
6
6
|
# emails passed into Mail.
|
|
7
7
|
#
|
|
@@ -18,57 +18,24 @@ module Mail
|
|
|
18
18
|
# a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
|
|
19
19
|
# a.group_names #=> ["My Group"]
|
|
20
20
|
def initialize(string)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return self
|
|
24
|
-
end
|
|
25
|
-
parser = Mail::AddressListsParser.new
|
|
26
|
-
if tree = parser.parse(string)
|
|
27
|
-
@address_nodes = tree.addresses
|
|
28
|
-
else
|
|
29
|
-
raise Mail::Field::ParseError.new(AddressListsParser, string, parser.failure_reason)
|
|
30
|
-
end
|
|
21
|
+
@addresses_grouped_by_group = nil
|
|
22
|
+
@address_list = Parsers::AddressListsParser.new.parse(string)
|
|
31
23
|
end
|
|
32
24
|
|
|
33
25
|
# Returns a list of address objects from the parsed line
|
|
34
26
|
def addresses
|
|
35
|
-
@addresses ||=
|
|
36
|
-
Mail::Address.new(
|
|
27
|
+
@addresses ||= @address_list.addresses.map do |address_data|
|
|
28
|
+
Mail::Address.new(address_data)
|
|
37
29
|
end
|
|
38
30
|
end
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@individual_recipients ||= @address_nodes - group_recipients
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Returns a list of all recipient syntax trees that are part of a group
|
|
46
|
-
def group_recipients # :nodoc:
|
|
47
|
-
@group_recipients ||= @address_nodes.select { |an| an.respond_to?(:group_name) }
|
|
31
|
+
|
|
32
|
+
def addresses_grouped_by_group
|
|
33
|
+
addresses.select(&:group).group_by(&:group)
|
|
48
34
|
end
|
|
49
35
|
|
|
50
36
|
# Returns the names as an array of strings of all groups
|
|
51
37
|
def group_names # :nodoc:
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Returns a list of address syntax trees
|
|
56
|
-
def address_nodes # :nodoc:
|
|
57
|
-
@address_nodes
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def get_addresses
|
|
63
|
-
(individual_recipients + group_recipients.map { |g| get_group_addresses(g) }).flatten
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def get_group_addresses(g)
|
|
67
|
-
if g.group_list.respond_to?(:addresses)
|
|
68
|
-
g.group_list.addresses
|
|
69
|
-
else
|
|
70
|
-
[]
|
|
71
|
-
end
|
|
38
|
+
@address_list.group_names
|
|
72
39
|
end
|
|
73
40
|
end
|
|
74
41
|
end
|
|
@@ -5,13 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@parameters = tree.parameters
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(ContentDispositionElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
8
|
+
content_disposition = Mail::Parsers::ContentDispositionParser.new.parse(cleaned(string))
|
|
9
|
+
@disposition_type = content_disposition.disposition_type
|
|
10
|
+
@parameters = content_disposition.parameters
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def disposition_type
|
|
@@ -5,12 +5,8 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@location = tree.location.text_value
|
|
11
|
-
else
|
|
12
|
-
raise Mail::Field::ParseError.new(ContentLocationElement, string, parser.failure_reason)
|
|
13
|
-
end
|
|
8
|
+
content_location = Mail::Parsers::ContentLocationParser.new.parse(string)
|
|
9
|
+
@location = content_location.location
|
|
14
10
|
end
|
|
15
11
|
|
|
16
12
|
def location
|