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
|
@@ -4,16 +4,9 @@ module Mail
|
|
|
4
4
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
when string.blank?
|
|
11
|
-
@encoding = ''
|
|
12
|
-
when tree = parser.parse(string.to_s.downcase)
|
|
13
|
-
@encoding = tree.encoding.text_value
|
|
14
|
-
else
|
|
15
|
-
raise Mail::Field::ParseError.new(ContentTransferEncodingElement, string, parser.failure_reason)
|
|
16
|
-
end
|
|
7
|
+
def initialize(string)
|
|
8
|
+
content_transfer_encoding = Mail::Parsers::ContentTransferEncodingParser.new.parse(string)
|
|
9
|
+
@encoding = content_transfer_encoding.encoding
|
|
17
10
|
end
|
|
18
11
|
|
|
19
12
|
def encoding
|
|
@@ -5,14 +5,10 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@parameters = tree.parameters
|
|
13
|
-
else
|
|
14
|
-
raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason)
|
|
15
|
-
end
|
|
8
|
+
content_type = Mail::Parsers::ContentTypeParser.new.parse(cleaned(string))
|
|
9
|
+
@main_type = content_type.main_type
|
|
10
|
+
@sub_type = content_type.sub_type
|
|
11
|
+
@parameters = content_type.parameters
|
|
16
12
|
end
|
|
17
13
|
|
|
18
14
|
def main_type
|
|
@@ -5,13 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@time_string = tree.time.text_value
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(DateTimeElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
8
|
+
date_time = Mail::Parsers::DateTimeParser.new.parse(string)
|
|
9
|
+
@date_string = date_time.date_string
|
|
10
|
+
@time_string = date_time.time_string
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def date_string
|
|
@@ -5,17 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@date_time = ::DateTime.parse("#{tree.ctime_date.text_value}")
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(EnvelopeFromElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def tree
|
|
18
|
-
@tree
|
|
8
|
+
@envelope_from = Mail::Parsers::EnvelopeFromParser.new.parse(string)
|
|
9
|
+
@address = @envelope_from.address
|
|
10
|
+
@date_time = ::DateTime.parse(@envelope_from.ctime_date)
|
|
19
11
|
end
|
|
20
12
|
|
|
21
13
|
def date_time
|
|
@@ -26,8 +18,21 @@ module Mail
|
|
|
26
18
|
@address
|
|
27
19
|
end
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
# RFC 4155:
|
|
22
|
+
# a timestamp indicating the UTC date and time when the message
|
|
23
|
+
# was originally received, conformant with the syntax of the
|
|
24
|
+
# traditional UNIX 'ctime' output sans timezone (note that the
|
|
25
|
+
# use of UTC precludes the need for a timezone indicator);
|
|
26
|
+
def formatted_date_time
|
|
27
|
+
if @date_time.respond_to?(:ctime)
|
|
28
|
+
@date_time.ctime
|
|
29
|
+
else
|
|
30
|
+
@date_time.strftime '%a %b %e %T %Y'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_s
|
|
35
|
+
"#{@address} #{formatted_date_time}"
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
end
|
|
@@ -5,12 +5,7 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize(string)
|
|
8
|
-
|
|
9
|
-
if tree = parser.parse(string)
|
|
10
|
-
@message_ids = tree.message_ids.map { |msg_id| clean_msg_id(msg_id.text_value) }
|
|
11
|
-
else
|
|
12
|
-
raise Mail::Field::ParseError.new(MessageIdsElement, string, parser.failure_reason)
|
|
13
|
-
end
|
|
8
|
+
@message_ids = Mail::Parsers::MessageIdsParser.new.parse(string).message_ids.map { |msg_id| clean_msg_id(msg_id) }
|
|
14
9
|
end
|
|
15
10
|
|
|
16
11
|
def message_ids
|
|
@@ -5,13 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@minor = tree.minor.text_value
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(MimeVersionElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
8
|
+
mime_version = Mail::Parsers::MimeVersionParser.new.parse(string)
|
|
9
|
+
@major = mime_version.major
|
|
10
|
+
@minor = mime_version.minor
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def major
|
|
@@ -5,16 +5,11 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize(string)
|
|
8
|
-
|
|
9
|
-
if tree = parser.parse(string)
|
|
10
|
-
@phrases = tree.phrases
|
|
11
|
-
else
|
|
12
|
-
raise Mail::Field::ParseError.new(PhraseList, string, parser.failure_reason)
|
|
13
|
-
end
|
|
8
|
+
@phrase_lists = Mail::Parsers::PhraseListsParser.new.parse(string)
|
|
14
9
|
end
|
|
15
10
|
|
|
16
11
|
def phrases
|
|
17
|
-
@phrases.map { |p| unquote(p
|
|
12
|
+
@phrase_lists.phrases.map { |p| unquote(p) }
|
|
18
13
|
end
|
|
19
14
|
|
|
20
15
|
end
|
|
@@ -5,13 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@info = tree.name_val_list.text_value
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(ReceivedElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
8
|
+
received = Mail::Parsers::ReceivedParser.new.parse(string)
|
|
9
|
+
@date_time = ::DateTime.parse("#{received.date} #{received.time}")
|
|
10
|
+
@info = received.info
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def date_time
|
data/lib/mail/elements.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Mail
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
register_autoload :Address, 'mail/elements/address'
|
|
3
|
+
register_autoload :AddressList, 'mail/elements/address_list'
|
|
4
|
+
register_autoload :ContentDispositionElement, 'mail/elements/content_disposition_element'
|
|
5
|
+
register_autoload :ContentLocationElement, 'mail/elements/content_location_element'
|
|
6
|
+
register_autoload :ContentTransferEncodingElement, 'mail/elements/content_transfer_encoding_element'
|
|
7
|
+
register_autoload :ContentTypeElement, 'mail/elements/content_type_element'
|
|
8
|
+
register_autoload :DateTimeElement, 'mail/elements/date_time_element'
|
|
9
|
+
register_autoload :EnvelopeFromElement, 'mail/elements/envelope_from_element'
|
|
10
|
+
register_autoload :MessageIdsElement, 'mail/elements/message_ids_element'
|
|
11
|
+
register_autoload :MimeVersionElement, 'mail/elements/mime_version_element'
|
|
12
|
+
register_autoload :PhraseList, 'mail/elements/phrase_list'
|
|
13
|
+
register_autoload :ReceivedElement, 'mail/elements/received_element'
|
|
14
14
|
end
|
|
@@ -12,13 +12,14 @@ module Mail
|
|
|
12
12
|
EightBit.can_encode? str
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
# Decode the string from Quoted-Printable
|
|
15
|
+
# Decode the string from Quoted-Printable. Cope with hard line breaks
|
|
16
|
+
# that were incorrectly encoded as hex instead of literal CRLF.
|
|
16
17
|
def self.decode(str)
|
|
17
|
-
str.unpack("M*").first
|
|
18
|
+
str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first.to_lf
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def self.encode(str)
|
|
21
|
-
[str].pack("M").
|
|
22
|
+
[str.to_lf].pack("M").to_crlf
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def self.cost(str)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Mail
|
|
2
|
+
module Encodings
|
|
3
|
+
module UnixToUnix
|
|
4
|
+
NAME = "x-uuencode"
|
|
5
|
+
|
|
6
|
+
def self.decode(str)
|
|
7
|
+
str.sub(/\Abegin \d+ [^\n]*\n/, '').unpack('u').first
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.encode(str)
|
|
11
|
+
[str].pack("u")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Encodings.register(NAME, self)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/mail/encodings.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Mail
|
|
|
7
7
|
|
|
8
8
|
module Encodings
|
|
9
9
|
|
|
10
|
-
include Mail::
|
|
10
|
+
include Mail::Constants
|
|
11
11
|
extend Mail::Utilities
|
|
12
12
|
|
|
13
13
|
@transfer_encodings = {}
|
|
@@ -47,13 +47,13 @@ module Mail
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def Encodings.get_name(enc)
|
|
50
|
-
enc = enc
|
|
50
|
+
enc = underscoreize(enc).downcase
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# Encodes a parameter value using URI Escaping, note the language field 'en' can
|
|
54
54
|
# be set using Mail::Configuration, like so:
|
|
55
55
|
#
|
|
56
|
-
# Mail.defaults
|
|
56
|
+
# Mail.defaults do
|
|
57
57
|
# param_encode_language 'jp'
|
|
58
58
|
# end
|
|
59
59
|
#
|
|
@@ -114,32 +114,16 @@ module Mail
|
|
|
114
114
|
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
|
115
115
|
def Encodings.value_decode(str)
|
|
116
116
|
# Optimization: If there's no encoded-words in the string, just return it
|
|
117
|
-
return str unless str
|
|
117
|
+
return str unless str =~ ENCODED_VALUE
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
lines = collapse_adjacent_encodings(str)
|
|
120
120
|
|
|
121
121
|
# Split on white-space boundaries with capture, so we capture the white-space as well
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
text.gsub!(/\?\=\=\?.+?\?[Qq]\?/m, '') if text =~ /\?==\?/
|
|
128
|
-
|
|
129
|
-
# Search for occurences of quoted strings or plain strings
|
|
130
|
-
text.scan(/( # Group around entire regex to include it in matches
|
|
131
|
-
\=\?[^?]+\?([QB])\?[^?]+?\?\= # Quoted String with subgroup for encoding method
|
|
132
|
-
| # or
|
|
133
|
-
.+?(?=\=\?|$) # Plain String
|
|
134
|
-
)/xmi).map do |matches|
|
|
135
|
-
string, method = *matches
|
|
136
|
-
if method == 'b' || method == 'B'
|
|
137
|
-
b_value_decode(string)
|
|
138
|
-
elsif method == 'q' || method == 'Q'
|
|
139
|
-
q_value_decode(string)
|
|
140
|
-
else
|
|
141
|
-
string
|
|
142
|
-
end
|
|
122
|
+
lines.each do |line|
|
|
123
|
+
line.gsub!(ENCODED_VALUE) do |string|
|
|
124
|
+
case $1
|
|
125
|
+
when *B_VALUES then b_value_decode(string)
|
|
126
|
+
when *Q_VALUES then q_value_decode(string)
|
|
143
127
|
end
|
|
144
128
|
end
|
|
145
129
|
end.join("")
|
|
@@ -147,19 +131,17 @@ module Mail
|
|
|
147
131
|
|
|
148
132
|
# Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
|
|
149
133
|
def Encodings.unquote_and_convert_to(str, to_encoding)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
output = value_decode( str ).to_s
|
|
134
|
+
output = value_decode( str ).to_s # output is already converted to UTF-8
|
|
153
135
|
|
|
154
|
-
if
|
|
136
|
+
if 'utf8' == to_encoding.to_s.downcase.gsub("-", "")
|
|
155
137
|
output
|
|
156
|
-
elsif
|
|
138
|
+
elsif to_encoding
|
|
157
139
|
begin
|
|
158
140
|
if RUBY_VERSION >= '1.9'
|
|
159
141
|
output.encode(to_encoding)
|
|
160
142
|
else
|
|
161
143
|
require 'iconv'
|
|
162
|
-
Iconv.iconv(to_encoding,
|
|
144
|
+
Iconv.iconv(to_encoding, 'UTF-8', output).first
|
|
163
145
|
end
|
|
164
146
|
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
|
|
165
147
|
# the 'from' parameter specifies a charset other than what the text
|
|
@@ -178,10 +160,10 @@ module Mail
|
|
|
178
160
|
def Encodings.address_encode(address, charset = 'utf-8')
|
|
179
161
|
if address.is_a?(Array)
|
|
180
162
|
# loop back through for each element
|
|
181
|
-
address.map { |a| Encodings.address_encode(a, charset) }.join(", ")
|
|
163
|
+
address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
|
|
182
164
|
else
|
|
183
165
|
# find any word boundary that is not ascii and encode it
|
|
184
|
-
encode_non_usascii(address, charset)
|
|
166
|
+
encode_non_usascii(address, charset) if address
|
|
185
167
|
end
|
|
186
168
|
end
|
|
187
169
|
|
|
@@ -189,15 +171,15 @@ module Mail
|
|
|
189
171
|
return address if address.ascii_only? or charset.nil?
|
|
190
172
|
us_ascii = %Q{\x00-\x7f}
|
|
191
173
|
# Encode any non usascii strings embedded inside of quotes
|
|
192
|
-
address.gsub
|
|
174
|
+
address = address.gsub(/(".*?[^#{us_ascii}].*?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
|
|
193
175
|
# Then loop through all remaining items and encode as needed
|
|
194
176
|
tokens = address.split(/\s/)
|
|
195
177
|
map_with_index(tokens) do |word, i|
|
|
196
178
|
if word.ascii_only?
|
|
197
179
|
word
|
|
198
180
|
else
|
|
199
|
-
previous_non_ascii = tokens[i-1] && !tokens[i-1].ascii_only?
|
|
200
|
-
if previous_non_ascii
|
|
181
|
+
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
|
|
182
|
+
if previous_non_ascii #why are we adding an extra space here?
|
|
201
183
|
word = " #{word}"
|
|
202
184
|
end
|
|
203
185
|
Encodings.b_value_encode(word, charset)
|
|
@@ -259,7 +241,7 @@ module Mail
|
|
|
259
241
|
end
|
|
260
242
|
|
|
261
243
|
def Encodings.split_encoding_from_string( str )
|
|
262
|
-
match = str.match(/\=\?([^?]+)?\?[QB]\?(
|
|
244
|
+
match = str.match(/\=\?([^?]+)?\?[QB]\?(.*)\?\=/mi)
|
|
263
245
|
if match
|
|
264
246
|
match[1]
|
|
265
247
|
else
|
|
@@ -270,5 +252,38 @@ module Mail
|
|
|
270
252
|
def Encodings.find_encoding(str)
|
|
271
253
|
RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
|
|
272
254
|
end
|
|
255
|
+
|
|
256
|
+
# Gets the encoding type (Q or B) from the string.
|
|
257
|
+
def Encodings.split_value_encoding_from_string(str)
|
|
258
|
+
match = str.match(/\=\?[^?]+?\?([QB])\?(.*)\?\=/mi)
|
|
259
|
+
if match
|
|
260
|
+
match[1]
|
|
261
|
+
else
|
|
262
|
+
nil
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# When the encoded string consists of multiple lines, lines with the same
|
|
267
|
+
# encoding (Q or B) can be joined together.
|
|
268
|
+
#
|
|
269
|
+
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
|
270
|
+
def Encodings.collapse_adjacent_encodings(str)
|
|
271
|
+
lines = str.split(/(\?=)\s*(=\?)/).each_slice(2).map(&:join)
|
|
272
|
+
results = []
|
|
273
|
+
previous_encoding = nil
|
|
274
|
+
|
|
275
|
+
lines.each do |line|
|
|
276
|
+
encoding = split_value_encoding_from_string(line)
|
|
277
|
+
|
|
278
|
+
if encoding == previous_encoding
|
|
279
|
+
line = results.pop + line
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
previous_encoding = encoding
|
|
283
|
+
results << line
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
results
|
|
287
|
+
end
|
|
273
288
|
end
|
|
274
289
|
end
|
data/lib/mail/envelope.rb
CHANGED
|
@@ -14,11 +14,6 @@ module Mail
|
|
|
14
14
|
super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def tree
|
|
18
|
-
@element ||= Mail::EnvelopeFromElement.new(value)
|
|
19
|
-
@tree ||= @element.tree
|
|
20
|
-
end
|
|
21
|
-
|
|
22
17
|
def element
|
|
23
18
|
@element ||= Mail::EnvelopeFromElement.new(value)
|
|
24
19
|
end
|