mail 2.7.1 → 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 +4 -4
- data/README.md +59 -28
- data/lib/mail/attachments_list.rb +2 -5
- data/lib/mail/body.rb +24 -47
- 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.rb +30 -59
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +37 -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 +46 -71
- 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 +52 -66
- data/lib/mail/multibyte/chars.rb +8 -166
- 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 +2 -2
- 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 +33070 -33064
- data/lib/mail/parsers/address_lists_parser.rl +7 -0
- data/lib/mail/parsers/content_disposition_parser.rb +833 -827
- data/lib/mail/parsers/content_disposition_parser.rl +7 -0
- data/lib/mail/parsers/content_location_parser.rb +770 -764
- data/lib/mail/parsers/content_location_parser.rl +7 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +474 -468
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
- data/lib/mail/parsers/content_type_parser.rb +971 -965
- data/lib/mail/parsers/content_type_parser.rl +7 -0
- data/lib/mail/parsers/date_time_parser.rb +838 -832
- data/lib/mail/parsers/date_time_parser.rl +7 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3623 -3529
- data/lib/mail/parsers/envelope_from_parser.rl +7 -0
- data/lib/mail/parsers/message_ids_parser.rb +5107 -2800
- data/lib/mail/parsers/message_ids_parser.rl +12 -1
- data/lib/mail/parsers/mime_version_parser.rb +463 -457
- data/lib/mail/parsers/mime_version_parser.rl +7 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +836 -830
- data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
- data/lib/mail/parsers/received_parser.rb +8688 -8682
- 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 +5 -9
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +307 -69
- data/lib/mail/version.rb +1 -1
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +3 -20
- metadata +72 -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)
|
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,6 +143,10 @@ 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
|
|
150
152
|
attr_reader :unparsed_value
|
@@ -163,10 +165,8 @@ module Mail
|
|
163
165
|
# # => #<Mail::Field …>
|
164
166
|
def initialize(name, value = nil, charset = 'utf-8')
|
165
167
|
case
|
166
|
-
when name.index(COLON)
|
167
|
-
|
168
|
-
@name, @unparsed_value = self.class.split(name)
|
169
|
-
@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.'
|
170
170
|
when Utilities.blank?(value)
|
171
171
|
@name = name
|
172
172
|
@unparsed_value = nil
|
@@ -179,8 +179,8 @@ module Mail
|
|
179
179
|
@name = FIELD_NAME_MAP[@name.to_s.downcase] || @name
|
180
180
|
end
|
181
181
|
|
182
|
-
def field=(
|
183
|
-
@field =
|
182
|
+
def field=(field)
|
183
|
+
@field = field
|
184
184
|
end
|
185
185
|
|
186
186
|
def field
|
@@ -209,81 +209,65 @@ module Mail
|
|
209
209
|
end.join(" ")}>"
|
210
210
|
end
|
211
211
|
|
212
|
-
def
|
213
|
-
|
214
|
-
end
|
215
|
-
|
216
|
-
def same( other )
|
217
|
-
return false unless other.kind_of?(self.class)
|
218
|
-
match_to_s(other.name, self.name)
|
212
|
+
def same(other)
|
213
|
+
other.kind_of?(self.class) && Utilities.match_to_s(other.name, name)
|
219
214
|
end
|
220
215
|
|
221
|
-
def ==(
|
222
|
-
|
223
|
-
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)
|
224
218
|
end
|
225
219
|
|
226
|
-
def responsible_for?(
|
227
|
-
name.to_s.casecmp(
|
220
|
+
def responsible_for?(field_name)
|
221
|
+
name.to_s.casecmp(field_name.to_s) == 0
|
228
222
|
end
|
229
223
|
|
230
|
-
def <=>(
|
231
|
-
|
224
|
+
def <=>(other)
|
225
|
+
field_order_id <=> other.field_order_id
|
232
226
|
end
|
233
227
|
|
234
228
|
def field_order_id
|
235
|
-
@field_order_id ||= (
|
229
|
+
@field_order_id ||= FIELD_ORDER_LOOKUP.fetch(self.name.to_s.downcase, 100)
|
236
230
|
end
|
237
231
|
|
238
232
|
def method_missing(name, *args, &block)
|
239
233
|
field.send(name, *args, &block)
|
240
234
|
end
|
241
235
|
|
242
|
-
|
243
|
-
|
244
|
-
field.respond_to?(method_name, include_private) || super
|
245
|
-
end
|
246
|
-
else
|
247
|
-
def respond_to?(method_name, include_private = false)
|
248
|
-
field.respond_to?(method_name, include_private) || super
|
249
|
-
end
|
236
|
+
def respond_to_missing?(method_name, include_private)
|
237
|
+
field.respond_to?(method_name, include_private) || super
|
250
238
|
end
|
251
239
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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]
|
262
250
|
|
263
251
|
private
|
264
252
|
|
265
253
|
def create_field(name, value, charset)
|
266
|
-
|
254
|
+
parse_field(name, value, charset)
|
267
255
|
rescue Mail::Field::ParseError => e
|
268
256
|
field = Mail::UnstructuredField.new(name, value)
|
269
257
|
field.errors << [name, value, e]
|
270
258
|
field
|
271
259
|
end
|
272
260
|
|
273
|
-
def
|
261
|
+
def parse_field(name, value, charset)
|
274
262
|
value = unfold(value) if value.is_a?(String)
|
275
263
|
|
276
|
-
if klass = field_class_for(name)
|
277
|
-
klass.
|
264
|
+
if klass = self.class.field_class_for(name)
|
265
|
+
klass.parse(value, charset)
|
278
266
|
else
|
279
|
-
OptionalField.
|
267
|
+
OptionalField.parse(name, value, charset)
|
280
268
|
end
|
281
269
|
end
|
282
270
|
|
283
|
-
def field_class_for(name)
|
284
|
-
FIELDS_MAP[name.to_s.downcase]
|
285
|
-
end
|
286
|
-
|
287
271
|
# 2.2.3. Long Header Fields
|
288
272
|
#
|
289
273
|
# The process of moving from this folded multiple-line representation
|
@@ -293,7 +277,7 @@ module Mail
|
|
293
277
|
# treated in its unfolded form for further syntactic and semantic
|
294
278
|
# evaluation.
|
295
279
|
def unfold(string)
|
296
|
-
string.gsub(
|
280
|
+
string.gsub(Constants::UNFOLD_WS, '\1')
|
297
281
|
end
|
298
282
|
end
|
299
283
|
end
|