mail 2.7.0 → 2.8.1
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 +5 -5
- data/README.md +59 -28
- data/lib/mail/attachments_list.rb +2 -5
- data/lib/mail/body.rb +33 -50
- data/lib/mail/check_delivery_params.rb +21 -16
- data/lib/mail/constants.rb +27 -5
- data/lib/mail/elements/address.rb +27 -27
- data/lib/mail/elements/address_list.rb +1 -1
- data/lib/mail/elements/content_disposition_element.rb +1 -1
- data/lib/mail/elements/content_location_element.rb +1 -1
- data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
- data/lib/mail/elements/content_type_element.rb +8 -4
- data/lib/mail/elements/date_time_element.rb +1 -1
- data/lib/mail/elements/envelope_from_element.rb +13 -7
- data/lib/mail/elements/message_ids_element.rb +14 -5
- data/lib/mail/elements/mime_version_element.rb +1 -1
- data/lib/mail/elements/phrase_list.rb +7 -2
- data/lib/mail/elements/received_element.rb +20 -6
- data/lib/mail/encodings/7bit.rb +5 -0
- data/lib/mail/encodings/base64.rb +2 -2
- data/lib/mail/encodings/quoted_printable.rb +2 -2
- data/lib/mail/encodings/transfer_encoding.rb +1 -1
- data/lib/mail/encodings/unix_to_unix.rb +1 -0
- data/lib/mail/encodings.rb +30 -59
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +39 -53
- data/lib/mail/field_list.rb +60 -7
- data/lib/mail/fields/bcc_field.rb +34 -52
- data/lib/mail/fields/cc_field.rb +28 -49
- data/lib/mail/fields/comments_field.rb +27 -37
- data/lib/mail/fields/common_address_field.rb +170 -0
- data/lib/mail/fields/common_date_field.rb +58 -0
- data/lib/mail/fields/common_field.rb +77 -0
- data/lib/mail/fields/common_message_id_field.rb +42 -0
- data/lib/mail/fields/content_description_field.rb +7 -14
- data/lib/mail/fields/content_disposition_field.rb +13 -38
- data/lib/mail/fields/content_id_field.rb +24 -51
- data/lib/mail/fields/content_location_field.rb +11 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
- data/lib/mail/fields/content_type_field.rb +47 -72
- data/lib/mail/fields/date_field.rb +23 -51
- data/lib/mail/fields/from_field.rb +28 -49
- data/lib/mail/fields/in_reply_to_field.rb +38 -49
- data/lib/mail/fields/keywords_field.rb +18 -31
- data/lib/mail/fields/message_id_field.rb +25 -71
- data/lib/mail/fields/mime_version_field.rb +19 -30
- data/lib/mail/fields/named_structured_field.rb +11 -0
- data/lib/mail/fields/named_unstructured_field.rb +11 -0
- data/lib/mail/fields/optional_field.rb +5 -6
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
- data/lib/mail/fields/received_field.rb +43 -57
- data/lib/mail/fields/references_field.rb +35 -49
- data/lib/mail/fields/reply_to_field.rb +28 -49
- data/lib/mail/fields/resent_bcc_field.rb +28 -49
- data/lib/mail/fields/resent_cc_field.rb +28 -49
- data/lib/mail/fields/resent_date_field.rb +5 -29
- data/lib/mail/fields/resent_from_field.rb +28 -49
- data/lib/mail/fields/resent_message_id_field.rb +5 -29
- data/lib/mail/fields/resent_sender_field.rb +27 -56
- data/lib/mail/fields/resent_to_field.rb +28 -49
- data/lib/mail/fields/return_path_field.rb +50 -54
- data/lib/mail/fields/sender_field.rb +34 -55
- data/lib/mail/fields/structured_field.rb +3 -30
- data/lib/mail/fields/subject_field.rb +9 -11
- data/lib/mail/fields/to_field.rb +28 -49
- data/lib/mail/fields/unstructured_field.rb +16 -48
- data/lib/mail/header.rb +69 -110
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/message.rb +53 -68
- data/lib/mail/multibyte/chars.rb +8 -166
- data/lib/mail/multibyte/unicode.rb +10 -10
- data/lib/mail/multibyte/utils.rb +26 -43
- data/lib/mail/multibyte.rb +1 -11
- data/lib/mail/network/delivery_methods/exim.rb +5 -4
- data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
- data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
- data/lib/mail/network/delivery_methods/sendmail.rb +56 -18
- data/lib/mail/network/delivery_methods/smtp.rb +25 -9
- data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -12
- data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
- data/lib/mail/network/retriever_methods/base.rb +8 -8
- data/lib/mail/network/retriever_methods/imap.rb +3 -3
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/parsers/address_lists_parser.rb +33175 -33140
- data/lib/mail/parsers/address_lists_parser.rl +7 -0
- data/lib/mail/parsers/content_disposition_parser.rb +889 -889
- data/lib/mail/parsers/content_disposition_parser.rl +7 -0
- data/lib/mail/parsers/content_location_parser.rb +796 -787
- data/lib/mail/parsers/content_location_parser.rl +7 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +496 -496
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
- data/lib/mail/parsers/content_type_parser.rb +1008 -1005
- data/lib/mail/parsers/content_type_parser.rl +7 -0
- data/lib/mail/parsers/date_time_parser.rb +864 -859
- data/lib/mail/parsers/date_time_parser.rl +7 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3649 -3548
- data/lib/mail/parsers/envelope_from_parser.rl +7 -0
- data/lib/mail/parsers/message_ids_parser.rb +5135 -2832
- data/lib/mail/parsers/message_ids_parser.rl +12 -1
- data/lib/mail/parsers/mime_version_parser.rb +487 -483
- data/lib/mail/parsers/mime_version_parser.rl +7 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +858 -865
- data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
- data/lib/mail/parsers/received_parser.rb +8756 -8728
- data/lib/mail/parsers/received_parser.rl +7 -0
- data/lib/mail/parsers/rfc5322.rl +28 -13
- data/lib/mail/parsers.rb +11 -17
- data/lib/mail/part.rb +6 -10
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +325 -87
- data/lib/mail/version.rb +2 -2
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +3 -20
- metadata +86 -18
- data/lib/mail/core_extensions/smtp.rb +0 -28
- data/lib/mail/core_extensions/string.rb +0 -17
- data/lib/mail/fields/common/address_container.rb +0 -17
- data/lib/mail/fields/common/common_address.rb +0 -161
- data/lib/mail/fields/common/common_date.rb +0 -36
- data/lib/mail/fields/common/common_field.rb +0 -52
- data/lib/mail/fields/common/common_message_id.rb +0 -49
- data/lib/mail/version_specific/ruby_1_8.rb +0 -163
- data/lib/mail/version_specific/ruby_1_9.rb +0 -278
@@ -4,13 +4,13 @@ require 'mail/parsers/envelope_from_parser'
|
|
4
4
|
require 'date'
|
5
5
|
|
6
6
|
module Mail
|
7
|
-
class EnvelopeFromElement
|
7
|
+
class EnvelopeFromElement #:nodoc:
|
8
8
|
attr_reader :date_time, :address
|
9
9
|
|
10
10
|
def initialize(string)
|
11
11
|
envelope_from = Mail::Parsers::EnvelopeFromParser.parse(string)
|
12
12
|
@address = envelope_from.address
|
13
|
-
@date_time = ::DateTime.parse(envelope_from.ctime_date)
|
13
|
+
@date_time = ::DateTime.parse(envelope_from.ctime_date) if envelope_from.ctime_date
|
14
14
|
end
|
15
15
|
|
16
16
|
# RFC 4155:
|
@@ -19,15 +19,21 @@ module Mail
|
|
19
19
|
# traditional UNIX 'ctime' output sans timezone (note that the
|
20
20
|
# use of UTC precludes the need for a timezone indicator);
|
21
21
|
def formatted_date_time
|
22
|
-
if date_time
|
23
|
-
date_time.ctime
|
24
|
-
|
25
|
-
|
22
|
+
if date_time
|
23
|
+
if date_time.respond_to?(:ctime)
|
24
|
+
date_time.ctime
|
25
|
+
else
|
26
|
+
date_time.strftime '%a %b %e %T %Y'
|
27
|
+
end
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def to_s
|
30
|
-
|
32
|
+
if date_time
|
33
|
+
"#{address} #{formatted_date_time}"
|
34
|
+
else
|
35
|
+
address
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
@@ -1,13 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'mail/parsers/message_ids_parser'
|
4
|
+
require 'mail/utilities'
|
4
5
|
|
5
6
|
module Mail
|
6
|
-
class MessageIdsElement
|
7
|
+
class MessageIdsElement #:nodoc:
|
8
|
+
def self.parse(string)
|
9
|
+
new(string).tap(&:message_ids)
|
10
|
+
end
|
11
|
+
|
7
12
|
attr_reader :message_ids
|
8
13
|
|
9
14
|
def initialize(string)
|
10
|
-
@message_ids =
|
15
|
+
@message_ids = parse(string)
|
11
16
|
end
|
12
17
|
|
13
18
|
def message_id
|
@@ -15,8 +20,12 @@ module Mail
|
|
15
20
|
end
|
16
21
|
|
17
22
|
private
|
18
|
-
|
19
|
-
|
20
|
-
|
23
|
+
def parse(string)
|
24
|
+
if Utilities.blank? string
|
25
|
+
[]
|
26
|
+
else
|
27
|
+
Mail::Parsers::MessageIdsParser.parse(string).message_ids
|
28
|
+
end
|
29
|
+
end
|
21
30
|
end
|
22
31
|
end
|
@@ -4,11 +4,16 @@ require 'mail/parsers/phrase_lists_parser'
|
|
4
4
|
require 'mail/utilities'
|
5
5
|
|
6
6
|
module Mail
|
7
|
-
class PhraseList
|
7
|
+
class PhraseList #:nodoc:
|
8
8
|
attr_reader :phrases
|
9
9
|
|
10
10
|
def initialize(string)
|
11
|
-
@phrases =
|
11
|
+
@phrases =
|
12
|
+
if Utilities.blank? string
|
13
|
+
[]
|
14
|
+
else
|
15
|
+
Mail::Parsers::PhraseListsParser.parse(string).phrases.map { |p| Mail::Utilities.unquote(p) }
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
@@ -1,21 +1,35 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'mail/parsers/received_parser'
|
4
|
+
require 'mail/utilities'
|
4
5
|
require 'date'
|
5
6
|
|
6
7
|
module Mail
|
7
|
-
class ReceivedElement
|
8
|
-
|
9
|
-
attr_reader :date_time, :info
|
8
|
+
class ReceivedElement #:nodoc:
|
9
|
+
attr_reader :info, :date_time
|
10
10
|
|
11
11
|
def initialize(string)
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
if Utilities.blank? string
|
13
|
+
@date_time = nil
|
14
|
+
@info = nil
|
15
|
+
else
|
16
|
+
received = Mail::Parsers::ReceivedParser.parse(string)
|
17
|
+
@date_time = datetime_for(received)
|
18
|
+
@info = received.info
|
19
|
+
end
|
15
20
|
end
|
16
21
|
|
17
22
|
def to_s(*args)
|
18
23
|
"#{info}; #{date_time.to_s(*args)}"
|
19
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def datetime_for(received)
|
28
|
+
::DateTime.parse("#{received.date} #{received.time}")
|
29
|
+
rescue ArgumentError => e
|
30
|
+
raise e unless e.message == 'invalid date'
|
31
|
+
warn "WARNING: Invalid date field for received element (#{received.date} #{received.time}): #{e.class}: #{e.message}"
|
32
|
+
nil
|
33
|
+
end
|
20
34
|
end
|
21
35
|
end
|
data/lib/mail/encodings/7bit.rb
CHANGED
@@ -17,6 +17,11 @@ module Mail
|
|
17
17
|
def self.encode(str)
|
18
18
|
::Mail::Utilities.binary_unsafe_to_crlf str
|
19
19
|
end
|
20
|
+
|
21
|
+
# Per RFC 2045 2.7. 7bit Data, No octets with decimal values greater than 127 are allowed.
|
22
|
+
def self.compatible_input?(str)
|
23
|
+
str.ascii_only? && super
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
@@ -16,11 +16,11 @@ module Mail
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.decode(str)
|
19
|
-
|
19
|
+
Utilities.decode_base64(str)
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.encode(str)
|
23
|
-
::Mail::Utilities.binary_unsafe_to_crlf(
|
23
|
+
::Mail::Utilities.binary_unsafe_to_crlf(Utilities.encode_base64(str))
|
24
24
|
end
|
25
25
|
|
26
26
|
# 3 bytes in -> 4 bytes out
|
@@ -16,11 +16,11 @@ module Mail
|
|
16
16
|
# Decode the string from Quoted-Printable. Cope with hard line breaks
|
17
17
|
# that were incorrectly encoded as hex instead of literal CRLF.
|
18
18
|
def self.decode(str)
|
19
|
-
str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
|
19
|
+
::Mail::Utilities.to_lf ::Mail::Utilities.to_crlf(str).gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.encode(str)
|
23
|
-
[str].pack("M")
|
23
|
+
::Mail::Utilities.to_crlf [::Mail::Utilities.to_lf(str)].pack("M")
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.cost(str)
|
@@ -33,7 +33,7 @@ module Mail
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def self.negotiate(message_encoding, source_encoding, str, allowed_encodings = nil)
|
36
|
-
message_encoding = Encodings.get_encoding(message_encoding || '8bit')
|
36
|
+
message_encoding = Encodings.get_encoding(message_encoding) || Encodings.get_encoding('8bit')
|
37
37
|
source_encoding = Encodings.get_encoding(source_encoding)
|
38
38
|
|
39
39
|
if message_encoding && source_encoding && message_encoding.can_transport?(source_encoding) && source_encoding.compatible_input?(str)
|
data/lib/mail/encodings.rb
CHANGED
@@ -52,7 +52,7 @@ module Mail
|
|
52
52
|
|
53
53
|
def Encodings.transcode_charset(str, from_charset, to_charset = 'UTF-8')
|
54
54
|
if from_charset
|
55
|
-
|
55
|
+
Utilities.transcode_charset str, from_charset, to_charset
|
56
56
|
else
|
57
57
|
str
|
58
58
|
end
|
@@ -65,8 +65,7 @@ module Mail
|
|
65
65
|
# param_encode_language 'jp'
|
66
66
|
# end
|
67
67
|
#
|
68
|
-
# The character set used for encoding will
|
69
|
-
# Ruby < 1.9 or the encoding on the string passed in.
|
68
|
+
# The character set used for encoding will be the encoding on the string passed in.
|
70
69
|
#
|
71
70
|
# Example:
|
72
71
|
#
|
@@ -78,7 +77,7 @@ module Mail
|
|
78
77
|
when str.ascii_only?
|
79
78
|
str
|
80
79
|
else
|
81
|
-
|
80
|
+
Utilities.param_encode(str)
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
@@ -92,15 +91,15 @@ module Mail
|
|
92
91
|
# str.encoding #=> 'ISO-8859-1' ## Only on Ruby 1.9
|
93
92
|
# str #=> "This is fun"
|
94
93
|
def Encodings.param_decode(str, encoding)
|
95
|
-
|
94
|
+
Utilities.param_decode(str, encoding)
|
96
95
|
end
|
97
96
|
|
98
97
|
# Decodes or encodes a string as needed for either Base64 or QP encoding types in
|
99
98
|
# the =?<encoding>?[QB]?<string>?=" format.
|
100
99
|
#
|
101
100
|
# The output type needs to be :decode to decode the input string or :encode to
|
102
|
-
# encode the input string. The character set used for encoding will
|
103
|
-
#
|
101
|
+
# encode the input string. The character set used for encoding will be the
|
102
|
+
# encoding on the string passed in.
|
104
103
|
#
|
105
104
|
# On encoding, will only send out Base64 encoded strings.
|
106
105
|
def Encodings.decode_encode(str, output_type)
|
@@ -111,7 +110,7 @@ module Mail
|
|
111
110
|
if str.ascii_only?
|
112
111
|
str
|
113
112
|
else
|
114
|
-
Encodings.b_value_encode(str,
|
113
|
+
Encodings.b_value_encode(str, str.encoding)
|
115
114
|
end
|
116
115
|
end
|
117
116
|
end
|
@@ -145,13 +144,8 @@ module Mail
|
|
145
144
|
output
|
146
145
|
elsif to_encoding
|
147
146
|
begin
|
148
|
-
|
149
|
-
|
150
|
-
else
|
151
|
-
require 'iconv'
|
152
|
-
Iconv.iconv(to_encoding, 'UTF-8', output).first
|
153
|
-
end
|
154
|
-
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
|
147
|
+
output.encode(to_encoding)
|
148
|
+
rescue Errno::EINVAL
|
155
149
|
# the 'from' parameter specifies a charset other than what the text
|
156
150
|
# actually is...not much we can do in this case but just return the
|
157
151
|
# unconverted text.
|
@@ -176,42 +170,23 @@ module Mail
|
|
176
170
|
def Encodings.encode_non_usascii(address, charset)
|
177
171
|
return address if address.ascii_only? or charset.nil?
|
178
172
|
|
179
|
-
#
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
# Then loop through all remaining items and encode as needed
|
185
|
-
tokens = address.split(/\s/)
|
186
|
-
|
187
|
-
map_with_index(tokens) do |word, i|
|
188
|
-
if word.ascii_only?
|
189
|
-
word
|
190
|
-
else
|
191
|
-
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
|
192
|
-
if previous_non_ascii #why are we adding an extra space here?
|
193
|
-
word = " #{word}"
|
194
|
-
end
|
195
|
-
Encodings.b_value_encode(word, charset)
|
196
|
-
end
|
197
|
-
end.join(' ')
|
198
|
-
end
|
199
|
-
end
|
173
|
+
# Encode all strings embedded inside of quotes
|
174
|
+
address = address.gsub(/("[^"]*[^\/]")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
|
175
|
+
|
176
|
+
# Then loop through all remaining items and encode as needed
|
177
|
+
tokens = address.split(/\s/)
|
200
178
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
179
|
+
map_with_index(tokens) do |word, i|
|
180
|
+
if word.ascii_only?
|
181
|
+
word
|
182
|
+
else
|
183
|
+
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
|
184
|
+
if previous_non_ascii #why are we adding an extra space here?
|
185
|
+
word = " #{word}"
|
186
|
+
end
|
187
|
+
Encodings.b_value_encode(word, charset)
|
206
188
|
end
|
207
|
-
|
208
|
-
ensure
|
209
|
-
$KCODE = original_kcode if original_kcode
|
210
|
-
end
|
211
|
-
else
|
212
|
-
def Encodings.with_ascii_kcode #:nodoc:
|
213
|
-
yield
|
214
|
-
end
|
189
|
+
end.join(' ')
|
215
190
|
end
|
216
191
|
|
217
192
|
# Encode a string with Base64 Encoding and returns it ready to be inserted
|
@@ -226,7 +201,7 @@ module Mail
|
|
226
201
|
string
|
227
202
|
else
|
228
203
|
Encodings.each_base64_chunk_byterange(string, 60).map do |chunk|
|
229
|
-
str, encoding =
|
204
|
+
str, encoding = Utilities.b_value_encode(chunk, encoding)
|
230
205
|
"=?#{encoding}?B?#{str.chomp}?="
|
231
206
|
end.join(" ")
|
232
207
|
end
|
@@ -241,7 +216,7 @@ module Mail
|
|
241
216
|
# #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="
|
242
217
|
def Encodings.q_value_encode(encoded_str, encoding = nil)
|
243
218
|
return encoded_str if encoded_str.to_s.ascii_only?
|
244
|
-
string, encoding =
|
219
|
+
string, encoding = Utilities.q_value_encode(encoded_str, encoding)
|
245
220
|
string.gsub!("=\r\n", '') # We already have limited the string to the length we want
|
246
221
|
map_lines(string) do |str|
|
247
222
|
"=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
|
@@ -257,7 +232,7 @@ module Mail
|
|
257
232
|
# Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
|
258
233
|
# #=> 'This is あ string'
|
259
234
|
def Encodings.b_value_decode(str)
|
260
|
-
|
235
|
+
Utilities.b_value_decode(str)
|
261
236
|
end
|
262
237
|
|
263
238
|
# Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format
|
@@ -267,11 +242,7 @@ module Mail
|
|
267
242
|
# Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
|
268
243
|
# #=> 'This is あ string'
|
269
244
|
def Encodings.q_value_decode(str)
|
270
|
-
|
271
|
-
end
|
272
|
-
|
273
|
-
def Encodings.find_encoding(str)
|
274
|
-
RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
|
245
|
+
Utilities.q_value_decode(str)
|
275
246
|
end
|
276
247
|
|
277
248
|
# Gets the encoding type (Q or B) from the string.
|
@@ -329,7 +300,7 @@ module Mail
|
|
329
300
|
charsize = chr.bytesize
|
330
301
|
|
331
302
|
if chunksize + charsize > max_bytesize_per_chunk
|
332
|
-
yield
|
303
|
+
yield Utilities.string_byteslice(str, offset, chunksize)
|
333
304
|
offset += chunksize
|
334
305
|
chunksize = charsize
|
335
306
|
else
|
@@ -337,7 +308,7 @@ module Mail
|
|
337
308
|
end
|
338
309
|
end
|
339
310
|
|
340
|
-
yield
|
311
|
+
yield Utilities.string_byteslice(str, offset, chunksize)
|
341
312
|
end
|
342
313
|
end
|
343
314
|
end
|
data/lib/mail/envelope.rb
CHANGED
@@ -1,31 +1,28 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
-
#
|
3
|
+
#
|
4
4
|
# = Mail Envelope
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# The Envelope class provides a field for the first line in an
|
7
7
|
# mbox file, that looks like "From mikel@test.lindsaar.net DATETIME"
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# This envelope class reads that line, and turns it into an
|
10
10
|
# Envelope.from and Envelope.date for your use.
|
11
|
+
|
11
12
|
module Mail
|
12
|
-
class Envelope <
|
13
|
-
|
14
|
-
|
15
|
-
super(FIELD_NAME, args.last.to_s)
|
16
|
-
end
|
17
|
-
|
13
|
+
class Envelope < NamedStructuredField
|
14
|
+
NAME = 'Envelope-From'
|
15
|
+
|
18
16
|
def element
|
19
17
|
@element ||= Mail::EnvelopeFromElement.new(value)
|
20
18
|
end
|
21
|
-
|
22
|
-
def date
|
23
|
-
::DateTime.parse("#{element.date_time}")
|
24
|
-
end
|
25
19
|
|
26
20
|
def from
|
27
21
|
element.address
|
28
22
|
end
|
29
|
-
|
23
|
+
|
24
|
+
def date
|
25
|
+
element.date_time
|
26
|
+
end
|
30
27
|
end
|
31
28
|
end
|
data/lib/mail/field.rb
CHANGED
@@ -23,8 +23,6 @@ module Mail
|
|
23
23
|
# sections 3 and 4 of this standard.
|
24
24
|
#
|
25
25
|
class Field
|
26
|
-
|
27
|
-
include Utilities
|
28
26
|
include Comparable
|
29
27
|
|
30
28
|
STRUCTURED_FIELDS = %w[ bcc cc content-description content-disposition
|
@@ -70,7 +68,7 @@ module Mail
|
|
70
68
|
}
|
71
69
|
|
72
70
|
FIELD_NAME_MAP = FIELDS_MAP.inject({}) do |map, (field, field_klass)|
|
73
|
-
map.update(field => field_klass::
|
71
|
+
map.update(field => field_klass::NAME)
|
74
72
|
end
|
75
73
|
|
76
74
|
# Generic Field Exception
|
@@ -121,7 +119,7 @@ module Mail
|
|
121
119
|
#
|
122
120
|
# Mail::Field.parse("field-name: field data")
|
123
121
|
# # => #<Mail::Field …>
|
124
|
-
def parse(field, charset =
|
122
|
+
def parse(field, charset = 'utf-8')
|
125
123
|
name, value = split(field)
|
126
124
|
if name && value
|
127
125
|
new name, value, charset
|
@@ -145,8 +143,14 @@ module Mail
|
|
145
143
|
warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: #{error.class}: #{error.message}"
|
146
144
|
nil
|
147
145
|
end
|
146
|
+
|
147
|
+
def field_class_for(name) #:nodoc:
|
148
|
+
FIELDS_MAP[name.to_s.downcase]
|
149
|
+
end
|
148
150
|
end
|
149
151
|
|
152
|
+
attr_reader :unparsed_value
|
153
|
+
|
150
154
|
# Create a field by name and optional value:
|
151
155
|
#
|
152
156
|
# Mail::Field.new("field-name", "value")
|
@@ -161,10 +165,8 @@ module Mail
|
|
161
165
|
# # => #<Mail::Field …>
|
162
166
|
def initialize(name, value = nil, charset = 'utf-8')
|
163
167
|
case
|
164
|
-
when name.index(COLON)
|
165
|
-
|
166
|
-
@name, @unparsed_value = self.class.split(name)
|
167
|
-
@charset = Utilities.blank?(value) ? charset : value
|
168
|
+
when name.index(Constants::COLON)
|
169
|
+
raise ArgumentError, 'Passing an unparsed header field to Mail::Field.new is not supported in Mail 2.8.0+. Use Mail::Field.parse instead.'
|
168
170
|
when Utilities.blank?(value)
|
169
171
|
@name = name
|
170
172
|
@unparsed_value = nil
|
@@ -177,8 +179,8 @@ module Mail
|
|
177
179
|
@name = FIELD_NAME_MAP[@name.to_s.downcase] || @name
|
178
180
|
end
|
179
181
|
|
180
|
-
def field=(
|
181
|
-
@field =
|
182
|
+
def field=(field)
|
183
|
+
@field = field
|
182
184
|
end
|
183
185
|
|
184
186
|
def field
|
@@ -207,81 +209,65 @@ module Mail
|
|
207
209
|
end.join(" ")}>"
|
208
210
|
end
|
209
211
|
|
210
|
-
def
|
211
|
-
|
212
|
-
end
|
213
|
-
|
214
|
-
def same( other )
|
215
|
-
return false unless other.kind_of?(self.class)
|
216
|
-
match_to_s(other.name, self.name)
|
212
|
+
def same(other)
|
213
|
+
other.kind_of?(self.class) && Utilities.match_to_s(other.name, name)
|
217
214
|
end
|
218
215
|
|
219
|
-
def ==(
|
220
|
-
|
221
|
-
match_to_s(other.name, self.name) && match_to_s(other.value, self.value)
|
216
|
+
def ==(other)
|
217
|
+
same(other) && Utilities.match_to_s(other.value, value)
|
222
218
|
end
|
223
219
|
|
224
|
-
def responsible_for?(
|
225
|
-
name.to_s.casecmp(
|
220
|
+
def responsible_for?(field_name)
|
221
|
+
name.to_s.casecmp(field_name.to_s) == 0
|
226
222
|
end
|
227
223
|
|
228
|
-
def <=>(
|
229
|
-
|
224
|
+
def <=>(other)
|
225
|
+
field_order_id <=> other.field_order_id
|
230
226
|
end
|
231
227
|
|
232
228
|
def field_order_id
|
233
|
-
@field_order_id ||= (
|
229
|
+
@field_order_id ||= FIELD_ORDER_LOOKUP.fetch(self.name.to_s.downcase, 100)
|
234
230
|
end
|
235
231
|
|
236
232
|
def method_missing(name, *args, &block)
|
237
233
|
field.send(name, *args, &block)
|
238
234
|
end
|
239
235
|
|
240
|
-
|
241
|
-
|
242
|
-
field.respond_to?(method_name, include_private) || super
|
243
|
-
end
|
244
|
-
else
|
245
|
-
def respond_to?(method_name, include_private = false)
|
246
|
-
field.respond_to?(method_name, include_private) || super
|
247
|
-
end
|
236
|
+
def respond_to_missing?(method_name, include_private)
|
237
|
+
field.respond_to?(method_name, include_private) || super
|
248
238
|
end
|
249
239
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
240
|
+
FIELD_ORDER_LOOKUP = Hash[%w[
|
241
|
+
return-path received
|
242
|
+
resent-date resent-from resent-sender resent-to
|
243
|
+
resent-cc resent-bcc resent-message-id
|
244
|
+
date from sender reply-to to cc bcc
|
245
|
+
message-id in-reply-to references
|
246
|
+
subject comments keywords
|
247
|
+
mime-version content-type content-transfer-encoding
|
248
|
+
content-location content-disposition content-description
|
249
|
+
].each_with_index.to_a]
|
260
250
|
|
261
251
|
private
|
262
252
|
|
263
253
|
def create_field(name, value, charset)
|
264
|
-
|
254
|
+
parse_field(name, value, charset)
|
265
255
|
rescue Mail::Field::ParseError => e
|
266
256
|
field = Mail::UnstructuredField.new(name, value)
|
267
257
|
field.errors << [name, value, e]
|
268
258
|
field
|
269
259
|
end
|
270
260
|
|
271
|
-
def
|
261
|
+
def parse_field(name, value, charset)
|
272
262
|
value = unfold(value) if value.is_a?(String)
|
273
263
|
|
274
|
-
if klass = field_class_for(name)
|
275
|
-
klass.
|
264
|
+
if klass = self.class.field_class_for(name)
|
265
|
+
klass.parse(value, charset)
|
276
266
|
else
|
277
|
-
OptionalField.
|
267
|
+
OptionalField.parse(name, value, charset)
|
278
268
|
end
|
279
269
|
end
|
280
270
|
|
281
|
-
def field_class_for(name)
|
282
|
-
FIELDS_MAP[name.to_s.downcase]
|
283
|
-
end
|
284
|
-
|
285
271
|
# 2.2.3. Long Header Fields
|
286
272
|
#
|
287
273
|
# The process of moving from this folded multiple-line representation
|
@@ -291,7 +277,7 @@ module Mail
|
|
291
277
|
# treated in its unfolded form for further syntactic and semantic
|
292
278
|
# evaluation.
|
293
279
|
def unfold(string)
|
294
|
-
string.gsub(
|
280
|
+
string.gsub(Constants::UNFOLD_WS, '\1')
|
295
281
|
end
|
296
282
|
end
|
297
283
|
end
|