mail 2.7.1 → 2.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|