mail 2.7.1 → 2.8.0

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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -28
  3. data/lib/mail/attachments_list.rb +2 -5
  4. data/lib/mail/body.rb +24 -47
  5. data/lib/mail/check_delivery_params.rb +21 -16
  6. data/lib/mail/constants.rb +27 -5
  7. data/lib/mail/elements/address.rb +27 -27
  8. data/lib/mail/elements/address_list.rb +1 -1
  9. data/lib/mail/elements/content_disposition_element.rb +1 -1
  10. data/lib/mail/elements/content_location_element.rb +1 -1
  11. data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
  12. data/lib/mail/elements/content_type_element.rb +8 -4
  13. data/lib/mail/elements/date_time_element.rb +1 -1
  14. data/lib/mail/elements/envelope_from_element.rb +13 -7
  15. data/lib/mail/elements/message_ids_element.rb +14 -5
  16. data/lib/mail/elements/mime_version_element.rb +1 -1
  17. data/lib/mail/elements/phrase_list.rb +7 -2
  18. data/lib/mail/elements/received_element.rb +20 -6
  19. data/lib/mail/encodings/7bit.rb +5 -0
  20. data/lib/mail/encodings/base64.rb +2 -2
  21. data/lib/mail/encodings/quoted_printable.rb +2 -2
  22. data/lib/mail/encodings.rb +30 -59
  23. data/lib/mail/envelope.rb +11 -14
  24. data/lib/mail/field.rb +37 -53
  25. data/lib/mail/field_list.rb +60 -7
  26. data/lib/mail/fields/bcc_field.rb +34 -52
  27. data/lib/mail/fields/cc_field.rb +28 -49
  28. data/lib/mail/fields/comments_field.rb +27 -37
  29. data/lib/mail/fields/common_address_field.rb +170 -0
  30. data/lib/mail/fields/common_date_field.rb +58 -0
  31. data/lib/mail/fields/common_field.rb +77 -0
  32. data/lib/mail/fields/common_message_id_field.rb +42 -0
  33. data/lib/mail/fields/content_description_field.rb +7 -14
  34. data/lib/mail/fields/content_disposition_field.rb +13 -38
  35. data/lib/mail/fields/content_id_field.rb +24 -51
  36. data/lib/mail/fields/content_location_field.rb +11 -25
  37. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
  38. data/lib/mail/fields/content_type_field.rb +46 -71
  39. data/lib/mail/fields/date_field.rb +23 -51
  40. data/lib/mail/fields/from_field.rb +28 -49
  41. data/lib/mail/fields/in_reply_to_field.rb +38 -49
  42. data/lib/mail/fields/keywords_field.rb +18 -31
  43. data/lib/mail/fields/message_id_field.rb +25 -71
  44. data/lib/mail/fields/mime_version_field.rb +19 -30
  45. data/lib/mail/fields/named_structured_field.rb +11 -0
  46. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  47. data/lib/mail/fields/optional_field.rb +5 -6
  48. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
  49. data/lib/mail/fields/received_field.rb +43 -57
  50. data/lib/mail/fields/references_field.rb +35 -49
  51. data/lib/mail/fields/reply_to_field.rb +28 -49
  52. data/lib/mail/fields/resent_bcc_field.rb +28 -49
  53. data/lib/mail/fields/resent_cc_field.rb +28 -49
  54. data/lib/mail/fields/resent_date_field.rb +5 -29
  55. data/lib/mail/fields/resent_from_field.rb +28 -49
  56. data/lib/mail/fields/resent_message_id_field.rb +5 -29
  57. data/lib/mail/fields/resent_sender_field.rb +27 -56
  58. data/lib/mail/fields/resent_to_field.rb +28 -49
  59. data/lib/mail/fields/return_path_field.rb +50 -54
  60. data/lib/mail/fields/sender_field.rb +34 -55
  61. data/lib/mail/fields/structured_field.rb +3 -30
  62. data/lib/mail/fields/subject_field.rb +9 -11
  63. data/lib/mail/fields/to_field.rb +28 -49
  64. data/lib/mail/fields/unstructured_field.rb +16 -48
  65. data/lib/mail/header.rb +69 -110
  66. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  67. data/lib/mail/message.rb +52 -66
  68. data/lib/mail/multibyte/chars.rb +8 -166
  69. data/lib/mail/multibyte/utils.rb +26 -43
  70. data/lib/mail/multibyte.rb +1 -11
  71. data/lib/mail/network/delivery_methods/exim.rb +5 -4
  72. data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
  73. data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
  74. data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
  75. data/lib/mail/network/delivery_methods/smtp.rb +25 -9
  76. data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -12
  77. data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
  78. data/lib/mail/network/retriever_methods/base.rb +8 -8
  79. data/lib/mail/network/retriever_methods/imap.rb +2 -2
  80. data/lib/mail/network/retriever_methods/pop3.rb +2 -2
  81. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  82. data/lib/mail/parsers/address_lists_parser.rb +33070 -33064
  83. data/lib/mail/parsers/address_lists_parser.rl +7 -0
  84. data/lib/mail/parsers/content_disposition_parser.rb +833 -827
  85. data/lib/mail/parsers/content_disposition_parser.rl +7 -0
  86. data/lib/mail/parsers/content_location_parser.rb +770 -764
  87. data/lib/mail/parsers/content_location_parser.rl +7 -0
  88. data/lib/mail/parsers/content_transfer_encoding_parser.rb +474 -468
  89. data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
  90. data/lib/mail/parsers/content_type_parser.rb +971 -965
  91. data/lib/mail/parsers/content_type_parser.rl +7 -0
  92. data/lib/mail/parsers/date_time_parser.rb +838 -832
  93. data/lib/mail/parsers/date_time_parser.rl +7 -0
  94. data/lib/mail/parsers/envelope_from_parser.rb +3623 -3529
  95. data/lib/mail/parsers/envelope_from_parser.rl +7 -0
  96. data/lib/mail/parsers/message_ids_parser.rb +5107 -2800
  97. data/lib/mail/parsers/message_ids_parser.rl +12 -1
  98. data/lib/mail/parsers/mime_version_parser.rb +463 -457
  99. data/lib/mail/parsers/mime_version_parser.rl +7 -0
  100. data/lib/mail/parsers/phrase_lists_parser.rb +836 -830
  101. data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
  102. data/lib/mail/parsers/received_parser.rb +8688 -8682
  103. data/lib/mail/parsers/received_parser.rl +7 -0
  104. data/lib/mail/parsers/rfc5322.rl +28 -13
  105. data/lib/mail/parsers.rb +11 -17
  106. data/lib/mail/part.rb +5 -9
  107. data/lib/mail/parts_list.rb +57 -0
  108. data/lib/mail/smtp_envelope.rb +57 -0
  109. data/lib/mail/utilities.rb +307 -69
  110. data/lib/mail/version.rb +2 -2
  111. data/lib/mail/yaml.rb +30 -0
  112. data/lib/mail.rb +3 -20
  113. metadata +72 -18
  114. data/lib/mail/core_extensions/smtp.rb +0 -28
  115. data/lib/mail/core_extensions/string.rb +0 -17
  116. data/lib/mail/fields/common/address_container.rb +0 -17
  117. data/lib/mail/fields/common/common_address.rb +0 -161
  118. data/lib/mail/fields/common/common_date.rb +0 -36
  119. data/lib/mail/fields/common/common_field.rb +0 -52
  120. data/lib/mail/fields/common/common_message_id.rb +0 -49
  121. data/lib/mail/version_specific/ruby_1_8.rb +0 -163
  122. data/lib/mail/version_specific/ruby_1_9.rb +0 -278
@@ -1,18 +1,15 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
3
  require 'mail/constants'
4
+ require 'socket'
4
5
 
5
6
  module Mail
6
7
  module Utilities
7
-
8
- LF = "\n"
9
- CRLF = "\r\n"
10
-
11
- include Constants
8
+ extend self
12
9
 
13
10
  # Returns true if the string supplied is free from characters not allowed as an ATOM
14
11
  def atom_safe?( str )
15
- not ATOM_UNSAFE === str
12
+ not Constants::ATOM_UNSAFE === str
16
13
  end
17
14
 
18
15
  # If the string supplied has ATOM unsafe characters in it, will return the string quoted
@@ -27,19 +24,19 @@ module Mail
27
24
  if str.respond_to?(:force_encoding)
28
25
  original_encoding = str.encoding
29
26
  ascii_str = str.to_s.dup.force_encoding('ASCII-8BIT')
30
- if (PHRASE_UNSAFE === ascii_str)
27
+ if Constants::PHRASE_UNSAFE === ascii_str
31
28
  dquote(ascii_str).force_encoding(original_encoding)
32
29
  else
33
30
  str
34
31
  end
35
32
  else
36
- (PHRASE_UNSAFE === str) ? dquote(str) : str
33
+ Constants::PHRASE_UNSAFE === str ? dquote(str) : str
37
34
  end
38
35
  end
39
36
 
40
37
  # Returns true if the string supplied is free from characters not allowed as a TOKEN
41
38
  def token_safe?( str )
42
- not TOKEN_UNSAFE === str
39
+ not Constants::TOKEN_UNSAFE === str
43
40
  end
44
41
 
45
42
  # If the string supplied has TOKEN unsafe characters in it, will return the string quoted
@@ -89,7 +86,6 @@ module Mail
89
86
  str
90
87
  end
91
88
  end
92
- module_function :unquote
93
89
 
94
90
  # Removes any \-escaping.
95
91
  #
@@ -103,7 +99,6 @@ module Mail
103
99
  def unescape( str )
104
100
  str.gsub(/\\(.)/, '\1')
105
101
  end
106
- module_function :unescape
107
102
 
108
103
  # Wraps a string in parenthesis and escapes any that are in the string itself.
109
104
  #
@@ -111,7 +106,7 @@ module Mail
111
106
  #
112
107
  # paren( 'This is a string' ) #=> '(This is a string)'
113
108
  def paren( str )
114
- RubyVer.paren( str )
109
+ Utilities.paren( str )
115
110
  end
116
111
 
117
112
  # Unwraps a string from being wrapped in parenthesis
@@ -121,8 +116,11 @@ module Mail
121
116
  # str = '(This is a string)'
122
117
  # unparen( str ) #=> 'This is a string'
123
118
  def unparen( str )
124
- match = str.match(/^\((.*?)\)$/)
125
- match ? match[1] : str
119
+ if str.start_with?('(') && str.end_with?(')')
120
+ str.slice(1..-2)
121
+ else
122
+ str
123
+ end
126
124
  end
127
125
 
128
126
  # Wraps a string in angle brackets and escapes any that are in the string itself
@@ -131,7 +129,7 @@ module Mail
131
129
  #
132
130
  # bracket( 'This is a string' ) #=> '<This is a string>'
133
131
  def bracket( str )
134
- RubyVer.bracket( str )
132
+ Utilities.bracket( str )
135
133
  end
136
134
 
137
135
  # Unwraps a string from being wrapped in parenthesis
@@ -141,8 +139,11 @@ module Mail
141
139
  # str = '<This is a string>'
142
140
  # unbracket( str ) #=> 'This is a string'
143
141
  def unbracket( str )
144
- match = str.match(/^\<(.*?)\>$/)
145
- match ? match[1] : str
142
+ if str.start_with?('<') && str.end_with?('>')
143
+ str.slice(1..-2)
144
+ else
145
+ str
146
+ end
146
147
  end
147
148
 
148
149
  # Escape parenthesies in a string
@@ -152,7 +153,7 @@ module Mail
152
153
  # str = 'This is (a) string'
153
154
  # escape_paren( str ) #=> 'This is \(a\) string'
154
155
  def escape_paren( str )
155
- RubyVer.escape_paren( str )
156
+ Utilities.escape_paren( str )
156
157
  end
157
158
 
158
159
  def uri_escape( str )
@@ -164,7 +165,7 @@ module Mail
164
165
  end
165
166
 
166
167
  def uri_parser
167
- @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
168
+ @uri_parser ||= URI.const_defined?(:DEFAULT_PARSER) ? URI::DEFAULT_PARSER : URI
168
169
  end
169
170
 
170
171
  # Matches two objects with their to_s values case insensitively
@@ -207,7 +208,7 @@ module Mail
207
208
  # string = :resent_from_field
208
209
  # dasherize( string ) #=> 'resent-from-field'
209
210
  def dasherize( str )
210
- str.to_s.tr(UNDERSCORE, HYPHEN)
211
+ str.to_s.tr(Constants::UNDERSCORE, Constants::HYPHEN)
211
212
  end
212
213
 
213
214
  # Swaps out all hyphens (-) for underscores (_) good for stringing to symbols
@@ -218,68 +219,36 @@ module Mail
218
219
  # string = :resent_from_field
219
220
  # underscoreize ( string ) #=> 'resent_from_field'
220
221
  def underscoreize( str )
221
- str.to_s.downcase.tr(HYPHEN, UNDERSCORE)
222
+ str.to_s.downcase.tr(Constants::HYPHEN, Constants::UNDERSCORE)
222
223
  end
223
224
 
224
- if RUBY_VERSION <= '1.8.6'
225
-
226
- def map_lines( str, &block )
227
- results = []
228
- str.each_line do |line|
229
- results << yield(line)
230
- end
231
- results
232
- end
233
-
234
- def map_with_index( enum, &block )
235
- results = []
236
- enum.each_with_index do |token, i|
237
- results[i] = yield(token, i)
238
- end
239
- results
240
- end
241
-
242
- else
243
-
244
- def map_lines( str, &block )
245
- str.each_line.map(&block)
246
- end
247
-
248
- def map_with_index( enum, &block )
249
- enum.each_with_index.map(&block)
250
- end
225
+ def map_lines( str, &block )
226
+ str.each_line.map(&block)
227
+ end
251
228
 
229
+ def map_with_index( enum, &block )
230
+ enum.each_with_index.map(&block)
252
231
  end
253
232
 
254
233
  def self.binary_unsafe_to_lf(string) #:nodoc:
255
- string.gsub(/\r\n|\r/, LF)
234
+ string.gsub(/\r\n|\r/, Constants::LF)
256
235
  end
257
236
 
258
237
  TO_CRLF_REGEX =
259
- if RUBY_VERSION >= '1.9'
260
- # This 1.9 only regex can save a reasonable amount of time (~20%)
261
- # by not matching "\r\n" so the string is returned unchanged in
262
- # the common case.
263
- Regexp.new("(?<!\r)\n|\r(?!\n)")
264
- else
265
- /\n|\r\n|\r/
266
- end
238
+ # This 1.9 only regex can save a reasonable amount of time (~20%)
239
+ # by not matching "\r\n" so the string is returned unchanged in
240
+ # the common case.
241
+ Regexp.new("(?<!\r)\n|\r(?!\n)")
267
242
 
268
243
  def self.binary_unsafe_to_crlf(string) #:nodoc:
269
- string.gsub(TO_CRLF_REGEX, CRLF)
244
+ string.gsub(TO_CRLF_REGEX, Constants::CRLF)
270
245
  end
271
246
 
272
- if RUBY_VERSION < '1.9'
273
- def self.safe_for_line_ending_conversion?(string) #:nodoc:
247
+ def self.safe_for_line_ending_conversion?(string) #:nodoc:
248
+ if string.encoding == Encoding::BINARY
274
249
  string.ascii_only?
275
- end
276
- else
277
- def self.safe_for_line_ending_conversion?(string) #:nodoc:
278
- if string.encoding == Encoding::BINARY
279
- string.ascii_only?
280
- else
281
- string.valid_encoding?
282
- end
250
+ else
251
+ string.valid_encoding?
283
252
  end
284
253
  end
285
254
 
@@ -311,7 +280,7 @@ module Mail
311
280
  # and arrays and hashes that have nothing in them.
312
281
  #
313
282
  # This logic is mostly shared with ActiveSupport's blank?
314
- def self.blank?(value)
283
+ def blank?(value)
315
284
  if value.kind_of?(NilClass)
316
285
  true
317
286
  elsif value.kind_of?(String)
@@ -320,5 +289,274 @@ module Mail
320
289
  value.respond_to?(:empty?) ? value.empty? : !value
321
290
  end
322
291
  end
292
+
293
+ def generate_message_id
294
+ "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
295
+ end
296
+
297
+ class StrictCharsetEncoder
298
+ def encode(string, charset)
299
+ case charset
300
+ when /utf-?7/i
301
+ Mail::Utilities.decode_utf7(string)
302
+ else
303
+ string.force_encoding(Mail::Utilities.pick_encoding(charset))
304
+ end
305
+ end
306
+ end
307
+
308
+ class BestEffortCharsetEncoder
309
+ def encode(string, charset)
310
+ case charset
311
+ when /utf-?7/i
312
+ Mail::Utilities.decode_utf7(string)
313
+ else
314
+ string.force_encoding(pick_encoding(charset))
315
+ end
316
+ end
317
+
318
+ private
319
+
320
+ def pick_encoding(charset)
321
+ charset = case charset
322
+ when /ansi_x3.110-1983/
323
+ 'ISO-8859-1'
324
+ when /Windows-?1258/i # Windows-1258 is similar to 1252
325
+ "Windows-1252"
326
+ else
327
+ charset
328
+ end
329
+ Mail::Utilities.pick_encoding(charset)
330
+ end
331
+ end
332
+
333
+ class << self
334
+ attr_accessor :charset_encoder
335
+ end
336
+ self.charset_encoder = BestEffortCharsetEncoder.new
337
+
338
+ # Escapes any parenthesis in a string that are unescaped this uses
339
+ # a Ruby 1.9.1 regexp feature of negative look behind
340
+ def Utilities.escape_paren( str )
341
+ re = /(?<!\\)([\(\)])/ # Only match unescaped parens
342
+ str.gsub(re) { |s| '\\' + s }
343
+ end
344
+
345
+ def Utilities.paren( str )
346
+ str = ::Mail::Utilities.unparen( str )
347
+ str = escape_paren( str )
348
+ '(' + str + ')'
349
+ end
350
+
351
+ def Utilities.escape_bracket( str )
352
+ re = /(?<!\\)([\<\>])/ # Only match unescaped brackets
353
+ str.gsub(re) { |s| '\\' + s }
354
+ end
355
+
356
+ def Utilities.bracket( str )
357
+ str = ::Mail::Utilities.unbracket( str )
358
+ str = escape_bracket( str )
359
+ '<' + str + '>'
360
+ end
361
+
362
+ def Utilities.decode_base64(str)
363
+ if !str.end_with?("=") && str.length % 4 != 0
364
+ str = str.ljust((str.length + 3) & ~3, "=")
365
+ end
366
+ str.unpack( 'm' ).first
367
+ end
368
+
369
+ def Utilities.encode_base64(str)
370
+ [str].pack( 'm' )
371
+ end
372
+
373
+ def Utilities.has_constant?(klass, string)
374
+ klass.const_defined?( string, false )
375
+ end
376
+
377
+ def Utilities.get_constant(klass, string)
378
+ klass.const_get( string )
379
+ end
380
+
381
+ def Utilities.transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8)
382
+ to_encoding = Encoding.find(to_encoding)
383
+ replacement_char = to_encoding == Encoding::UTF_8 ? '�' : '?'
384
+ charset_encoder.encode(str.dup, from_encoding).encode(to_encoding, :undef => :replace, :invalid => :replace, :replace => replacement_char)
385
+ end
386
+
387
+ # From Ruby stdlib Net::IMAP
388
+ def Utilities.encode_utf7(string)
389
+ string.gsub(/(&)|[^\x20-\x7e]+/) do
390
+ if $1
391
+ "&-"
392
+ else
393
+ base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0")
394
+ "&" + base64.delete("=").tr("/", ",") + "-"
395
+ end
396
+ end.force_encoding(Encoding::ASCII_8BIT)
397
+ end
398
+
399
+ def Utilities.decode_utf7(utf7)
400
+ utf7.gsub(/&([^-]+)?-/n) do
401
+ if $1
402
+ ($1.tr(",", "/") + "===").unpack("m")[0].encode(Encoding::UTF_8, Encoding::UTF_16BE)
403
+ else
404
+ "&"
405
+ end
406
+ end
407
+ end
408
+
409
+ def Utilities.b_value_encode(str, encoding = nil)
410
+ encoding = str.encoding.to_s
411
+ [Utilities.encode_base64(str), encoding]
412
+ end
413
+
414
+ def Utilities.b_value_decode(str)
415
+ match = str.match(/\=\?(.+)?\?[Bb]\?(.*)\?\=/m)
416
+ if match
417
+ charset = match[1]
418
+ str = Utilities.decode_base64(match[2])
419
+ str = charset_encoder.encode(str, charset)
420
+ end
421
+ transcode_to_scrubbed_utf8(str)
422
+ rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError, Encoding::InvalidByteSequenceError
423
+ warn "Encoding conversion failed #{$!}"
424
+ str.dup.force_encoding(Encoding::UTF_8)
425
+ end
426
+
427
+ def Utilities.q_value_encode(str, encoding = nil)
428
+ encoding = str.encoding.to_s
429
+ [Encodings::QuotedPrintable.encode(str), encoding]
430
+ end
431
+
432
+ def Utilities.q_value_decode(str)
433
+ match = str.match(/\=\?(.+)?\?[Qq]\?(.*)\?\=/m)
434
+ if match
435
+ charset = match[1]
436
+ string = match[2].gsub(/_/, '=20')
437
+ # Remove trailing = if it exists in a Q encoding
438
+ string = string.sub(/\=$/, '')
439
+ str = Encodings::QuotedPrintable.decode(string)
440
+ str = charset_encoder.encode(str, charset)
441
+ # We assume that binary strings hold utf-8 directly to work around
442
+ # jruby/jruby#829 which subtly changes String#encode semantics.
443
+ str.force_encoding(Encoding::UTF_8) if str.encoding == Encoding::ASCII_8BIT
444
+ end
445
+ transcode_to_scrubbed_utf8(str)
446
+ rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
447
+ warn "Encoding conversion failed #{$!}"
448
+ str.dup.force_encoding(Encoding::UTF_8)
449
+ end
450
+
451
+ def Utilities.param_decode(str, encoding)
452
+ str = uri_parser.unescape(str)
453
+ str = charset_encoder.encode(str, encoding) if encoding
454
+ transcode_to_scrubbed_utf8(str)
455
+ rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
456
+ warn "Encoding conversion failed #{$!}"
457
+ str.dup.force_encoding(Encoding::UTF_8)
458
+ end
459
+
460
+ def Utilities.param_encode(str)
461
+ encoding = str.encoding.to_s.downcase
462
+ language = Configuration.instance.param_encode_language
463
+ "#{encoding}'#{language}'#{uri_parser.escape(str)}"
464
+ end
465
+
466
+ def Utilities.uri_parser
467
+ URI::DEFAULT_PARSER
468
+ end
469
+
470
+ # Pick a Ruby encoding corresponding to the message charset. Most
471
+ # charsets have a Ruby encoding, but some need manual aliasing here.
472
+ #
473
+ # TODO: add this as a test somewhere:
474
+ # Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b}
475
+ # Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b}
476
+ def Utilities.pick_encoding(charset)
477
+ charset = charset.to_s
478
+ encoding = case charset.downcase
479
+
480
+ # ISO-8859-8-I etc. http://en.wikipedia.org/wiki/ISO-8859-8-I
481
+ when /^iso[-_]?8859-(\d+)(-i)?$/
482
+ "ISO-8859-#{$1}"
483
+
484
+ # ISO-8859-15, ISO-2022-JP and alike
485
+ when /^iso[-_]?(\d{4})-?(\w{1,2})$/
486
+ "ISO-#{$1}-#{$2}"
487
+
488
+ # "ISO-2022-JP-KDDI" and alike
489
+ when /^iso[-_]?(\d{4})-?(\w{1,2})-?(\w*)$/
490
+ "ISO-#{$1}-#{$2}-#{$3}"
491
+
492
+ # UTF-8, UTF-32BE and alike
493
+ when /^utf[\-_]?(\d{1,2})?(\w{1,2})$/
494
+ "UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE')
495
+
496
+ # Windows-1252 and alike
497
+ when /^windows-?(.*)$/
498
+ "Windows-#{$1}"
499
+
500
+ when '8bit'
501
+ Encoding::ASCII_8BIT
502
+
503
+ # alternatives/misspellings of us-ascii seen in the wild
504
+ when /^iso[-_]?646(-us)?$/, 'us=ascii'
505
+ Encoding::ASCII
506
+
507
+ # Microsoft-specific alias for MACROMAN
508
+ when 'macintosh'
509
+ Encoding::MACROMAN
510
+
511
+ # Microsoft-specific alias for CP949 (Korean)
512
+ when 'ks_c_5601-1987'
513
+ Encoding::CP949
514
+
515
+ # Wrongly written Shift_JIS (Japanese)
516
+ when 'shift-jis'
517
+ Encoding::Shift_JIS
518
+
519
+ # GB2312 (Chinese charset) is a subset of GB18030 (its replacement)
520
+ when 'gb2312'
521
+ Encoding::GB18030
522
+
523
+ when 'cp-850'
524
+ Encoding::CP850
525
+
526
+ when 'latin2'
527
+ Encoding::ISO_8859_2
528
+
529
+ else
530
+ charset
531
+ end
532
+
533
+ convert_to_encoding(encoding)
534
+ end
535
+
536
+ def Utilities.string_byteslice(str, *args)
537
+ str.byteslice(*args)
538
+ end
539
+
540
+ class << self
541
+ private
542
+
543
+ def convert_to_encoding(encoding)
544
+ if encoding.is_a?(Encoding)
545
+ encoding
546
+ else
547
+ # Fall back to ASCII for charsets that Ruby doesn't recognize
548
+ begin
549
+ Encoding.find(encoding)
550
+ rescue ArgumentError
551
+ Encoding::BINARY
552
+ end
553
+ end
554
+ end
555
+
556
+ def transcode_to_scrubbed_utf8(str)
557
+ decoded = str.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => "�")
558
+ decoded.valid_encoding? ? decoded : decoded.encode(Encoding::UTF_16LE, :invalid => :replace, :replace => "�").encode(Encoding::UTF_8)
559
+ end
560
+ end
323
561
  end
324
562
  end
data/lib/mail/version.rb CHANGED
@@ -3,8 +3,8 @@ module Mail
3
3
  module VERSION
4
4
 
5
5
  MAJOR = 2
6
- MINOR = 7
7
- PATCH = 1
6
+ MINOR = 8
7
+ PATCH = 0
8
8
  BUILD = nil
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
data/lib/mail/yaml.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'yaml'
2
+
3
+ module Mail
4
+ module YAML
5
+ def self.load(yaml)
6
+ permitted_classes = [
7
+ Symbol,
8
+
9
+ Mail::Body,
10
+
11
+ # Delivery methods as listed in mail/configuration.rb
12
+ Mail::SMTP,
13
+ Mail::Sendmail,
14
+ Mail::Exim,
15
+ Mail::FileDelivery,
16
+ Mail::SMTPConnection,
17
+ Mail::TestMailer,
18
+ Mail::LoggerDelivery,
19
+
20
+ Mail.delivery_method.class,
21
+ ]
22
+
23
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0.pre1')
24
+ ::YAML.safe_load(yaml, :permitted_classes => permitted_classes)
25
+ else
26
+ ::YAML.safe_load(yaml, permitted_classes)
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/mail.rb CHANGED
@@ -9,26 +9,8 @@ module Mail # :doc:
9
9
  require 'net/smtp'
10
10
  require 'mini_mime'
11
11
 
12
- if RUBY_VERSION <= '1.8.6'
13
- begin
14
- require 'tlsmail'
15
- rescue LoadError
16
- raise "You need to install tlsmail if you are using ruby <= 1.8.6"
17
- end
18
- end
19
-
20
- if RUBY_VERSION >= "1.9.0"
21
- require 'mail/version_specific/ruby_1_9'
22
- RubyVer = Ruby19
23
- else
24
- require 'mail/version_specific/ruby_1_8'
25
- RubyVer = Ruby18
26
- end
27
-
28
12
  require 'mail/version'
29
13
 
30
- require 'mail/core_extensions/string'
31
- require 'mail/core_extensions/smtp'
32
14
  require 'mail/indifferent_hash'
33
15
 
34
16
  require 'mail/multibyte'
@@ -68,8 +50,6 @@ module Mail # :doc:
68
50
 
69
51
  require 'mail/envelope'
70
52
 
71
- register_autoload :Parsers, "mail/parsers"
72
-
73
53
  # Autoload header field elements and transfer encodings.
74
54
  require 'mail/elements'
75
55
  require 'mail/encodings'
@@ -80,6 +60,9 @@ module Mail # :doc:
80
60
  require 'mail/matchers/has_sent_mail'
81
61
  require 'mail/matchers/attachment_matchers.rb'
82
62
 
63
+ # Deprecated will be removed in 3.0 release
64
+ require 'mail/check_delivery_params'
65
+
83
66
  # Finally... require all the Mail.methods
84
67
  require 'mail/mail'
85
68
  end