mail 2.5.2 → 2.6.4
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 +124 -0
- data/CONTRIBUTING.md +21 -6
- data/Dependencies.txt +0 -1
- data/Gemfile +7 -22
- data/MIT-LICENSE +20 -0
- data/README.md +86 -31
- data/Rakefile +11 -22
- data/lib/mail/attachments_list.rb +4 -2
- data/lib/mail/body.rb +36 -11
- data/lib/mail/check_delivery_params.rb +13 -22
- data/lib/mail/configuration.rb +1 -0
- data/lib/mail/{patterns.rb → constants.rb} +29 -6
- data/lib/mail/core_extensions/smtp.rb +13 -13
- data/lib/mail/core_extensions/string/access.rb +1 -0
- data/lib/mail/core_extensions/string/multibyte.rb +1 -0
- data/lib/mail/core_extensions/string.rb +5 -17
- data/lib/mail/elements/address.rb +86 -145
- data/lib/mail/elements/address_list.rb +10 -42
- data/lib/mail/elements/content_disposition_element.rb +4 -7
- data/lib/mail/elements/content_location_element.rb +8 -11
- data/lib/mail/elements/content_transfer_encoding_element.rb +4 -10
- data/lib/mail/elements/content_type_element.rb +5 -8
- data/lib/mail/elements/date_time_element.rb +4 -7
- data/lib/mail/elements/envelope_from_element.rb +19 -13
- data/lib/mail/elements/message_ids_element.rb +8 -11
- data/lib/mail/elements/mime_version_element.rb +4 -7
- data/lib/mail/elements/phrase_list.rb +3 -7
- data/lib/mail/elements/received_element.rb +4 -7
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +1 -0
- data/lib/mail/encodings/8bit.rb +8 -2
- data/lib/mail/encodings/base64.rb +7 -1
- data/lib/mail/encodings/binary.rb +1 -0
- data/lib/mail/encodings/quoted_printable.rb +11 -4
- data/lib/mail/encodings/transfer_encoding.rb +27 -17
- data/lib/mail/encodings/unix_to_unix.rb +18 -0
- data/lib/mail/encodings.rb +54 -39
- data/lib/mail/envelope.rb +1 -5
- data/lib/mail/field.rb +81 -31
- data/lib/mail/field_list.rb +19 -18
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +3 -3
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +1 -0
- data/lib/mail/fields/common/common_address.rb +34 -28
- data/lib/mail/fields/common/common_date.rb +2 -8
- data/lib/mail/fields/common/common_field.rb +9 -5
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +4 -3
- data/lib/mail/fields/content_description_field.rb +1 -0
- data/lib/mail/fields/content_disposition_field.rb +13 -12
- data/lib/mail/fields/content_id_field.rb +4 -4
- data/lib/mail/fields/content_location_field.rb +2 -1
- data/lib/mail/fields/content_transfer_encoding_field.rb +4 -9
- data/lib/mail/fields/content_type_field.rb +4 -3
- data/lib/mail/fields/date_field.rb +16 -15
- data/lib/mail/fields/from_field.rb +3 -3
- data/lib/mail/fields/in_reply_to_field.rb +3 -1
- data/lib/mail/fields/keywords_field.rb +2 -2
- data/lib/mail/fields/message_id_field.rb +4 -4
- data/lib/mail/fields/mime_version_field.rb +3 -2
- data/lib/mail/fields/optional_field.rb +1 -0
- data/lib/mail/fields/received_field.rb +4 -3
- data/lib/mail/fields/references_field.rb +3 -1
- data/lib/mail/fields/reply_to_field.rb +3 -3
- data/lib/mail/fields/resent_bcc_field.rb +3 -3
- data/lib/mail/fields/resent_cc_field.rb +3 -3
- data/lib/mail/fields/resent_date_field.rb +2 -1
- data/lib/mail/fields/resent_from_field.rb +3 -3
- data/lib/mail/fields/resent_message_id_field.rb +1 -0
- data/lib/mail/fields/resent_sender_field.rb +4 -4
- data/lib/mail/fields/resent_to_field.rb +3 -3
- data/lib/mail/fields/return_path_field.rb +1 -1
- data/lib/mail/fields/sender_field.rb +9 -9
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +1 -0
- data/lib/mail/fields/to_field.rb +3 -3
- data/lib/mail/fields/unstructured_field.rb +15 -8
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +21 -29
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +16 -1
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +61 -4
- data/lib/mail/message.rb +175 -72
- data/lib/mail/multibyte/chars.rb +3 -2
- data/lib/mail/multibyte/exceptions.rb +1 -0
- data/lib/mail/multibyte/unicode.rb +22 -15
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +1 -0
- data/lib/mail/network/delivery_methods/exim.rb +3 -7
- data/lib/mail/network/delivery_methods/file_delivery.rb +2 -1
- data/lib/mail/network/delivery_methods/sendmail.rb +33 -10
- data/lib/mail/network/delivery_methods/smtp.rb +32 -34
- data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +3 -2
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -13
- data/lib/mail/network/retriever_methods/pop3.rb +1 -0
- data/lib/mail/network/retriever_methods/test_retriever.rb +1 -0
- data/lib/mail/network.rb +1 -0
- data/lib/mail/parsers/address_lists_parser.rb +133 -0
- data/lib/mail/parsers/content_disposition_parser.rb +68 -0
- data/lib/mail/parsers/content_location_parser.rb +36 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +34 -0
- data/lib/mail/parsers/content_type_parser.rb +67 -0
- data/lib/mail/parsers/date_time_parser.rb +39 -0
- data/lib/mail/parsers/envelope_from_parser.rb +46 -0
- data/lib/mail/parsers/message_ids_parser.rb +40 -0
- data/lib/mail/parsers/mime_version_parser.rb +42 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +36 -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 +18 -0
- data/lib/mail/parsers/received_parser.rb +49 -0
- data/lib/mail/parsers.rb +27 -0
- data/lib/mail/part.rb +11 -4
- data/lib/mail/parts_list.rb +30 -10
- data/lib/mail/utilities.rb +127 -63
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/version_specific/ruby_1_8.rb +18 -7
- data/lib/mail/version_specific/ruby_1_9.rb +136 -32
- data/lib/mail.rb +12 -6
- metadata +115 -77
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -41
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- 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 -5397
- 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,17 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class ContentDispositionElement # :nodoc:
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
content_disposition = Mail::Parsers::ContentDispositionParser.new.parse(cleaned(string))
|
|
10
|
+
@disposition_type = content_disposition.disposition_type
|
|
11
|
+
@parameters = content_disposition.parameters
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
def disposition_type
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class ContentLocationElement # :nodoc:
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
include Mail::Utilities
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
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
|
|
9
|
+
content_location = Mail::Parsers::ContentLocationParser.new.parse(string)
|
|
10
|
+
@location = content_location.location
|
|
14
11
|
end
|
|
15
|
-
|
|
12
|
+
|
|
16
13
|
def location
|
|
17
14
|
@location
|
|
18
15
|
end
|
|
19
|
-
|
|
16
|
+
|
|
20
17
|
def to_s(*args)
|
|
21
18
|
location.to_s
|
|
22
19
|
end
|
|
23
|
-
|
|
20
|
+
|
|
24
21
|
end
|
|
25
22
|
end
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class ContentTransferEncodingElement
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
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
|
|
8
|
+
def initialize(string)
|
|
9
|
+
content_transfer_encoding = Mail::Parsers::ContentTransferEncodingParser.new.parse(string)
|
|
10
|
+
@encoding = content_transfer_encoding.encoding
|
|
17
11
|
end
|
|
18
12
|
|
|
19
13
|
def encoding
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class ContentTypeElement # :nodoc:
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
content_type = Mail::Parsers::ContentTypeParser.new.parse(cleaned(string))
|
|
10
|
+
@main_type = content_type.main_type
|
|
11
|
+
@sub_type = content_type.sub_type
|
|
12
|
+
@parameters = content_type.parameters
|
|
16
13
|
end
|
|
17
14
|
|
|
18
15
|
def main_type
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class DateTimeElement # :nodoc:
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
date_time = Mail::Parsers::DateTimeParser.new.parse(string)
|
|
10
|
+
@date_string = date_time.date_string
|
|
11
|
+
@time_string = date_time.time_string
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
def date_string
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class EnvelopeFromElement
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
@envelope_from = Mail::Parsers::EnvelopeFromParser.new.parse(string)
|
|
10
|
+
@address = @envelope_from.address
|
|
11
|
+
@date_time = ::DateTime.parse(@envelope_from.ctime_date)
|
|
19
12
|
end
|
|
20
13
|
|
|
21
14
|
def date_time
|
|
@@ -26,8 +19,21 @@ module Mail
|
|
|
26
19
|
@address
|
|
27
20
|
end
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
# RFC 4155:
|
|
23
|
+
# a timestamp indicating the UTC date and time when the message
|
|
24
|
+
# was originally received, conformant with the syntax of the
|
|
25
|
+
# traditional UNIX 'ctime' output sans timezone (note that the
|
|
26
|
+
# use of UTC precludes the need for a timezone indicator);
|
|
27
|
+
def formatted_date_time
|
|
28
|
+
if @date_time.respond_to?(:ctime)
|
|
29
|
+
@date_time.ctime
|
|
30
|
+
else
|
|
31
|
+
@date_time.strftime '%a %b %e %T %Y'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_s
|
|
36
|
+
"#{@address} #{formatted_date_time}"
|
|
31
37
|
end
|
|
32
38
|
|
|
33
39
|
end
|
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class MessageIdsElement
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
include Mail::Utilities
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
def initialize(string)
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
9
|
+
raise Mail::Field::ParseError.new(Mail::MessageIdsElement, string, 'nil is invalid') if string.nil?
|
|
10
|
+
@message_ids = Mail::Parsers::MessageIdsParser.new.parse(string).message_ids.map { |msg_id| clean_msg_id(msg_id) }
|
|
14
11
|
end
|
|
15
|
-
|
|
12
|
+
|
|
16
13
|
def message_ids
|
|
17
14
|
@message_ids
|
|
18
15
|
end
|
|
19
|
-
|
|
16
|
+
|
|
20
17
|
def message_id
|
|
21
18
|
@message_ids.first
|
|
22
19
|
end
|
|
23
|
-
|
|
20
|
+
|
|
24
21
|
def clean_msg_id( val )
|
|
25
22
|
val =~ /.*<(.*)>.*/ ; $1
|
|
26
23
|
end
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class MimeVersionElement
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
mime_version = Mail::Parsers::MimeVersionParser.new.parse(string)
|
|
10
|
+
@major = mime_version.major
|
|
11
|
+
@minor = mime_version.minor
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
def major
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class PhraseList
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
@phrase_lists = Mail::Parsers::PhraseListsParser.new.parse(string)
|
|
14
10
|
end
|
|
15
11
|
|
|
16
12
|
def phrases
|
|
17
|
-
@phrases.map { |p| unquote(p
|
|
13
|
+
@phrase_lists.phrases.map { |p| unquote(p) }
|
|
18
14
|
end
|
|
19
15
|
|
|
20
16
|
end
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class ReceivedElement
|
|
4
5
|
|
|
5
6
|
include Mail::Utilities
|
|
6
7
|
|
|
7
8
|
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
|
|
9
|
+
received = Mail::Parsers::ReceivedParser.new.parse(string)
|
|
10
|
+
@date_time = ::DateTime.parse("#{received.date} #{received.time}")
|
|
11
|
+
@info = received.info
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
def date_time
|
data/lib/mail/elements.rb
CHANGED
data/lib/mail/encodings/7bit.rb
CHANGED
data/lib/mail/encodings/8bit.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
require 'mail/encodings/binary'
|
|
3
4
|
|
|
4
5
|
module Mail
|
|
@@ -12,12 +13,12 @@ module Mail
|
|
|
12
13
|
|
|
13
14
|
# Decode the string
|
|
14
15
|
def self.decode(str)
|
|
15
|
-
|
|
16
|
+
::Mail::Utilities.to_lf str
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# Encode the string
|
|
19
20
|
def self.encode(str)
|
|
20
|
-
|
|
21
|
+
::Mail::Utilities.to_crlf str
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
# Idenity encodings have a fixed cost, 1 byte out per 1 byte in
|
|
@@ -25,6 +26,11 @@ module Mail
|
|
|
25
26
|
1.0
|
|
26
27
|
end
|
|
27
28
|
|
|
29
|
+
# Per RFC 2821 4.5.3.1, SMTP lines may not be longer than 1000 octets including the <CRLF>.
|
|
30
|
+
def self.compatible_input?(str)
|
|
31
|
+
!str.lines.find { |line| line.length > 998 }
|
|
32
|
+
end
|
|
33
|
+
|
|
28
34
|
Encodings.register(NAME, self)
|
|
29
35
|
end
|
|
30
36
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
require 'mail/encodings/7bit'
|
|
3
4
|
|
|
4
5
|
module Mail
|
|
@@ -19,7 +20,7 @@ module Mail
|
|
|
19
20
|
|
|
20
21
|
# Encode the string to Base64
|
|
21
22
|
def self.encode(str)
|
|
22
|
-
RubyVer.encode_base64( str )
|
|
23
|
+
::Mail::Utilities.to_crlf(RubyVer.encode_base64( str ))
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
# Base64 has a fixed cost, 4 bytes out per 3 bytes in
|
|
@@ -27,6 +28,11 @@ module Mail
|
|
|
27
28
|
4.0/3
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
# Base64 inserts newlines automatically and cannot violate the SMTP spec.
|
|
32
|
+
def self.compatible_input?(str)
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
Encodings.register(NAME, self)
|
|
31
37
|
end
|
|
32
38
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
require 'mail/encodings/7bit'
|
|
3
4
|
|
|
4
5
|
module Mail
|
|
@@ -12,13 +13,14 @@ module Mail
|
|
|
12
13
|
EightBit.can_encode? str
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
# Decode the string from Quoted-Printable
|
|
16
|
+
# Decode the string from Quoted-Printable. Cope with hard line breaks
|
|
17
|
+
# that were incorrectly encoded as hex instead of literal CRLF.
|
|
16
18
|
def self.decode(str)
|
|
17
|
-
str.unpack("M*").first
|
|
19
|
+
::Mail::Utilities.to_lf str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def self.encode(str)
|
|
21
|
-
[str].pack("M")
|
|
23
|
+
::Mail::Utilities.to_crlf([::Mail::Utilities.to_lf(str)].pack("M"))
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def self.cost(str)
|
|
@@ -29,7 +31,12 @@ module Mail
|
|
|
29
31
|
total = (str.bytesize - c)*3 + c
|
|
30
32
|
total.to_f/str.bytesize
|
|
31
33
|
end
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
# QP inserts newlines automatically and cannot violate the SMTP spec.
|
|
36
|
+
def self.compatible_input?(str)
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
|
|
33
40
|
private
|
|
34
41
|
|
|
35
42
|
Encodings.register(NAME, self)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
module Encodings
|
|
4
5
|
class TransferEncoding
|
|
@@ -23,30 +24,39 @@ module Mail
|
|
|
23
24
|
raise "Unimplemented"
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
def self.compatible_input?(str)
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def self.to_s
|
|
27
32
|
self::NAME
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
def self.get_best_compatible(source_encoding, str)
|
|
31
|
-
if self.can_transport?
|
|
32
|
-
|
|
36
|
+
if self.can_transport?(source_encoding) && self.compatible_input?(str)
|
|
37
|
+
source_encoding
|
|
33
38
|
else
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
choices = Encodings.get_all.select do |enc|
|
|
40
|
+
self.can_transport?(enc) && enc.can_encode?(source_encoding)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
best = nil
|
|
44
|
+
best_cost = nil
|
|
45
|
+
|
|
46
|
+
choices.each do |enc|
|
|
47
|
+
# If the current choice cannot be transported safely,
|
|
48
|
+
# give priority to other choices but allow it to be used as a fallback.
|
|
49
|
+
this_cost = enc.cost(str) if enc.compatible_input?(str)
|
|
50
|
+
|
|
51
|
+
if !best_cost || (this_cost && this_cost < best_cost)
|
|
52
|
+
best_cost = this_cost
|
|
53
|
+
best = enc
|
|
54
|
+
elsif this_cost == best_cost
|
|
55
|
+
best = enc if enc::PRIORITY < best::PRIORITY
|
|
48
56
|
end
|
|
49
|
-
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
best
|
|
50
60
|
end
|
|
51
61
|
end
|
|
52
62
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Mail
|
|
3
|
+
module Encodings
|
|
4
|
+
module UnixToUnix
|
|
5
|
+
NAME = "x-uuencode"
|
|
6
|
+
|
|
7
|
+
def self.decode(str)
|
|
8
|
+
str.sub(/\Abegin \d+ [^\n]*\n/, '').unpack('u').first
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.encode(str)
|
|
12
|
+
[str].pack("u")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Encodings.register(NAME, self)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/mail/encodings.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Mail
|
|
4
5
|
# Raised when attempting to decode an unknown encoding type
|
|
@@ -7,7 +8,7 @@ module Mail
|
|
|
7
8
|
|
|
8
9
|
module Encodings
|
|
9
10
|
|
|
10
|
-
include Mail::
|
|
11
|
+
include Mail::Constants
|
|
11
12
|
extend Mail::Utilities
|
|
12
13
|
|
|
13
14
|
@transfer_encodings = {}
|
|
@@ -47,13 +48,21 @@ module Mail
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def Encodings.get_name(enc)
|
|
50
|
-
enc
|
|
51
|
+
underscoreize(enc).downcase
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def Encodings.transcode_charset(str, from_charset, to_charset = 'UTF-8')
|
|
55
|
+
if from_charset
|
|
56
|
+
RubyVer.transcode_charset str, from_charset, to_charset
|
|
57
|
+
else
|
|
58
|
+
str
|
|
59
|
+
end
|
|
51
60
|
end
|
|
52
61
|
|
|
53
62
|
# Encodes a parameter value using URI Escaping, note the language field 'en' can
|
|
54
63
|
# be set using Mail::Configuration, like so:
|
|
55
64
|
#
|
|
56
|
-
# Mail.defaults
|
|
65
|
+
# Mail.defaults do
|
|
57
66
|
# param_encode_language 'jp'
|
|
58
67
|
# end
|
|
59
68
|
#
|
|
@@ -114,32 +123,16 @@ module Mail
|
|
|
114
123
|
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
|
115
124
|
def Encodings.value_decode(str)
|
|
116
125
|
# Optimization: If there's no encoded-words in the string, just return it
|
|
117
|
-
return str unless str
|
|
126
|
+
return str unless str =~ ENCODED_VALUE
|
|
118
127
|
|
|
119
|
-
|
|
128
|
+
lines = collapse_adjacent_encodings(str)
|
|
120
129
|
|
|
121
130
|
# 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
|
|
131
|
+
lines.each do |line|
|
|
132
|
+
line.gsub!(ENCODED_VALUE) do |string|
|
|
133
|
+
case $2
|
|
134
|
+
when *B_VALUES then b_value_decode(string)
|
|
135
|
+
when *Q_VALUES then q_value_decode(string)
|
|
143
136
|
end
|
|
144
137
|
end
|
|
145
138
|
end.join("")
|
|
@@ -148,7 +141,7 @@ module Mail
|
|
|
148
141
|
# Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
|
|
149
142
|
def Encodings.unquote_and_convert_to(str, to_encoding)
|
|
150
143
|
output = value_decode( str ).to_s # output is already converted to UTF-8
|
|
151
|
-
|
|
144
|
+
|
|
152
145
|
if 'utf8' == to_encoding.to_s.downcase.gsub("-", "")
|
|
153
146
|
output
|
|
154
147
|
elsif to_encoding
|
|
@@ -157,7 +150,7 @@ module Mail
|
|
|
157
150
|
output.encode(to_encoding)
|
|
158
151
|
else
|
|
159
152
|
require 'iconv'
|
|
160
|
-
Iconv.iconv(to_encoding, 'UTF-8', output).first
|
|
153
|
+
Iconv.iconv(to_encoding, 'UTF-8', output).first
|
|
161
154
|
end
|
|
162
155
|
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
|
|
163
156
|
# the 'from' parameter specifies a charset other than what the text
|
|
@@ -194,8 +187,8 @@ module Mail
|
|
|
194
187
|
if word.ascii_only?
|
|
195
188
|
word
|
|
196
189
|
else
|
|
197
|
-
previous_non_ascii = tokens[i-1] && !tokens[i-1].ascii_only?
|
|
198
|
-
if previous_non_ascii
|
|
190
|
+
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
|
|
191
|
+
if previous_non_ascii #why are we adding an extra space here?
|
|
199
192
|
word = " #{word}"
|
|
200
193
|
end
|
|
201
194
|
Encodings.b_value_encode(word, charset)
|
|
@@ -256,17 +249,39 @@ module Mail
|
|
|
256
249
|
RubyVer.q_value_decode(str)
|
|
257
250
|
end
|
|
258
251
|
|
|
259
|
-
def Encodings.split_encoding_from_string( str )
|
|
260
|
-
match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi)
|
|
261
|
-
if match
|
|
262
|
-
match[1]
|
|
263
|
-
else
|
|
264
|
-
nil
|
|
265
|
-
end
|
|
266
|
-
end
|
|
267
|
-
|
|
268
252
|
def Encodings.find_encoding(str)
|
|
269
253
|
RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
|
|
270
254
|
end
|
|
255
|
+
|
|
256
|
+
# Gets the encoding type (Q or B) from the string.
|
|
257
|
+
def Encodings.value_encoding_from_string(str)
|
|
258
|
+
str[ENCODED_VALUE, 1]
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# When the encoded string consists of multiple lines, lines with the same
|
|
262
|
+
# encoding (Q or B) can be joined together.
|
|
263
|
+
#
|
|
264
|
+
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
|
265
|
+
def Encodings.collapse_adjacent_encodings(str)
|
|
266
|
+
results = []
|
|
267
|
+
previous_encoding = nil
|
|
268
|
+
lines = str.split(FULL_ENCODED_VALUE)
|
|
269
|
+
lines.each_slice(2) do |unencoded, encoded|
|
|
270
|
+
if encoded
|
|
271
|
+
encoding = value_encoding_from_string(encoded)
|
|
272
|
+
if encoding == previous_encoding && Utilities.blank?(unencoded)
|
|
273
|
+
results.last << encoded
|
|
274
|
+
else
|
|
275
|
+
results << unencoded unless unencoded == EMPTY
|
|
276
|
+
results << encoded
|
|
277
|
+
end
|
|
278
|
+
previous_encoding = encoding
|
|
279
|
+
else
|
|
280
|
+
results << unencoded
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
results
|
|
285
|
+
end
|
|
271
286
|
end
|
|
272
287
|
end
|
data/lib/mail/envelope.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# = Mail Envelope
|
|
4
5
|
#
|
|
@@ -14,11 +15,6 @@ module Mail
|
|
|
14
15
|
super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
def tree
|
|
18
|
-
@element ||= Mail::EnvelopeFromElement.new(value)
|
|
19
|
-
@tree ||= @element.tree
|
|
20
|
-
end
|
|
21
|
-
|
|
22
18
|
def element
|
|
23
19
|
@element ||= Mail::EnvelopeFromElement.new(value)
|
|
24
20
|
end
|