mail 2.6.6 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +134 -119
  4. data/lib/mail/attachments_list.rb +10 -9
  5. data/lib/mail/body.rb +73 -84
  6. data/lib/mail/check_delivery_params.rb +28 -21
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/constants.rb +27 -5
  9. data/lib/mail/elements/address.rb +53 -47
  10. data/lib/mail/elements/address_list.rb +11 -19
  11. data/lib/mail/elements/content_disposition_element.rb +9 -16
  12. data/lib/mail/elements/content_location_element.rb +6 -11
  13. data/lib/mail/elements/content_transfer_encoding_element.rb +6 -11
  14. data/lib/mail/elements/content_type_element.rb +16 -23
  15. data/lib/mail/elements/date_time_element.rb +7 -15
  16. data/lib/mail/elements/envelope_from_element.rb +22 -23
  17. data/lib/mail/elements/message_ids_element.rb +18 -13
  18. data/lib/mail/elements/mime_version_element.rb +7 -15
  19. data/lib/mail/elements/phrase_list.rb +12 -10
  20. data/lib/mail/elements/received_element.rb +27 -19
  21. data/lib/mail/encodings/7bit.rb +9 -14
  22. data/lib/mail/encodings/8bit.rb +2 -21
  23. data/lib/mail/encodings/base64.rb +11 -12
  24. data/lib/mail/encodings/binary.rb +3 -22
  25. data/lib/mail/encodings/identity.rb +24 -0
  26. data/lib/mail/encodings/quoted_printable.rb +6 -6
  27. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  28. data/lib/mail/encodings/unix_to_unix.rb +3 -1
  29. data/lib/mail/encodings.rb +81 -54
  30. data/lib/mail/envelope.rb +11 -14
  31. data/lib/mail/field.rb +119 -98
  32. data/lib/mail/field_list.rb +60 -7
  33. data/lib/mail/fields/bcc_field.rb +34 -52
  34. data/lib/mail/fields/cc_field.rb +28 -49
  35. data/lib/mail/fields/comments_field.rb +27 -37
  36. data/lib/mail/fields/common_address_field.rb +170 -0
  37. data/lib/mail/fields/common_date_field.rb +58 -0
  38. data/lib/mail/fields/common_field.rb +77 -0
  39. data/lib/mail/fields/common_message_id_field.rb +42 -0
  40. data/lib/mail/fields/content_description_field.rb +7 -14
  41. data/lib/mail/fields/content_disposition_field.rb +13 -38
  42. data/lib/mail/fields/content_id_field.rb +24 -51
  43. data/lib/mail/fields/content_location_field.rb +11 -25
  44. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
  45. data/lib/mail/fields/content_type_field.rb +50 -80
  46. data/lib/mail/fields/date_field.rb +23 -52
  47. data/lib/mail/fields/from_field.rb +28 -49
  48. data/lib/mail/fields/in_reply_to_field.rb +38 -49
  49. data/lib/mail/fields/keywords_field.rb +18 -31
  50. data/lib/mail/fields/message_id_field.rb +25 -71
  51. data/lib/mail/fields/mime_version_field.rb +19 -30
  52. data/lib/mail/fields/named_structured_field.rb +11 -0
  53. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  54. data/lib/mail/fields/optional_field.rb +9 -7
  55. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +13 -11
  56. data/lib/mail/fields/received_field.rb +43 -57
  57. data/lib/mail/fields/references_field.rb +35 -49
  58. data/lib/mail/fields/reply_to_field.rb +28 -49
  59. data/lib/mail/fields/resent_bcc_field.rb +28 -49
  60. data/lib/mail/fields/resent_cc_field.rb +28 -49
  61. data/lib/mail/fields/resent_date_field.rb +5 -30
  62. data/lib/mail/fields/resent_from_field.rb +28 -49
  63. data/lib/mail/fields/resent_message_id_field.rb +5 -29
  64. data/lib/mail/fields/resent_sender_field.rb +27 -56
  65. data/lib/mail/fields/resent_to_field.rb +28 -49
  66. data/lib/mail/fields/return_path_field.rb +50 -54
  67. data/lib/mail/fields/sender_field.rb +34 -55
  68. data/lib/mail/fields/structured_field.rb +3 -30
  69. data/lib/mail/fields/subject_field.rb +9 -11
  70. data/lib/mail/fields/to_field.rb +28 -49
  71. data/lib/mail/fields/unstructured_field.rb +32 -47
  72. data/lib/mail/header.rb +71 -110
  73. data/lib/mail/mail.rb +2 -10
  74. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  75. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  76. data/lib/mail/message.rb +113 -117
  77. data/lib/mail/multibyte/chars.rb +21 -178
  78. data/lib/mail/multibyte/unicode.rb +10 -10
  79. data/lib/mail/multibyte/utils.rb +26 -43
  80. data/lib/mail/multibyte.rb +55 -16
  81. data/lib/mail/network/delivery_methods/exim.rb +5 -4
  82. data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
  83. data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  84. data/lib/mail/network/delivery_methods/sendmail.rb +62 -21
  85. data/lib/mail/network/delivery_methods/smtp.rb +75 -50
  86. data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -4
  87. data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
  88. data/lib/mail/network/retriever_methods/base.rb +8 -8
  89. data/lib/mail/network/retriever_methods/imap.rb +20 -7
  90. data/lib/mail/network/retriever_methods/pop3.rb +5 -3
  91. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  92. data/lib/mail/network.rb +1 -0
  93. data/lib/mail/parser_tools.rb +15 -0
  94. data/lib/mail/parsers/address_lists_parser.rb +33225 -116
  95. data/lib/mail/parsers/address_lists_parser.rl +179 -0
  96. data/lib/mail/parsers/content_disposition_parser.rb +882 -49
  97. data/lib/mail/parsers/content_disposition_parser.rl +89 -0
  98. data/lib/mail/parsers/content_location_parser.rb +809 -23
  99. data/lib/mail/parsers/content_location_parser.rl +78 -0
  100. data/lib/mail/parsers/content_transfer_encoding_parser.rb +509 -21
  101. data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
  102. data/lib/mail/parsers/content_type_parser.rb +1037 -56
  103. data/lib/mail/parsers/content_type_parser.rl +90 -0
  104. data/lib/mail/parsers/date_time_parser.rb +877 -25
  105. data/lib/mail/parsers/date_time_parser.rl +69 -0
  106. data/lib/mail/parsers/envelope_from_parser.rb +3669 -40
  107. data/lib/mail/parsers/envelope_from_parser.rl +89 -0
  108. data/lib/mail/parsers/message_ids_parser.rb +5146 -25
  109. data/lib/mail/parsers/message_ids_parser.rl +93 -0
  110. data/lib/mail/parsers/mime_version_parser.rb +497 -26
  111. data/lib/mail/parsers/mime_version_parser.rl +68 -0
  112. data/lib/mail/parsers/phrase_lists_parser.rb +870 -22
  113. data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
  114. data/lib/mail/parsers/received_parser.rb +8776 -43
  115. data/lib/mail/parsers/received_parser.rl +91 -0
  116. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  117. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  118. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  119. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  120. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  121. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  122. data/lib/mail/parsers/rfc5322.rl +74 -0
  123. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  124. data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
  125. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  126. data/lib/mail/parsers.rb +11 -25
  127. data/lib/mail/part.rb +6 -10
  128. data/lib/mail/parts_list.rb +62 -6
  129. data/lib/mail/smtp_envelope.rb +57 -0
  130. data/lib/mail/utilities.rb +343 -74
  131. data/lib/mail/version.rb +2 -2
  132. data/lib/mail/yaml.rb +30 -0
  133. data/lib/mail.rb +5 -35
  134. metadata +111 -66
  135. data/CHANGELOG.rdoc +0 -803
  136. data/CONTRIBUTING.md +0 -60
  137. data/Dependencies.txt +0 -2
  138. data/Gemfile +0 -14
  139. data/Rakefile +0 -29
  140. data/TODO.rdoc +0 -9
  141. data/lib/mail/core_extensions/smtp.rb +0 -25
  142. data/lib/mail/core_extensions/string/access.rb +0 -146
  143. data/lib/mail/core_extensions/string/multibyte.rb +0 -79
  144. data/lib/mail/core_extensions/string.rb +0 -21
  145. data/lib/mail/fields/common/address_container.rb +0 -17
  146. data/lib/mail/fields/common/common_address.rb +0 -136
  147. data/lib/mail/fields/common/common_date.rb +0 -36
  148. data/lib/mail/fields/common/common_field.rb +0 -61
  149. data/lib/mail/fields/common/common_message_id.rb +0 -49
  150. data/lib/mail/multibyte/exceptions.rb +0 -9
  151. data/lib/mail/parsers/ragel/common.rl +0 -185
  152. data/lib/mail/parsers/ragel/parser_info.rb +0 -61
  153. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
  154. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
  155. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
  156. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
  157. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
  158. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
  159. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
  160. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
  161. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
  162. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
  163. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
  164. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
  165. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
  166. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
  167. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
  168. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
  169. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
  170. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
  171. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
  172. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
  173. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
  174. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
  175. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
  176. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
  177. data/lib/mail/parsers/ragel/ruby.rb +0 -40
  178. data/lib/mail/parsers/ragel.rb +0 -18
  179. data/lib/mail/version_specific/ruby_1_8.rb +0 -126
  180. data/lib/mail/version_specific/ruby_1_9.rb +0 -226
@@ -7,17 +7,17 @@ module Mail
7
7
 
8
8
  PRIORITY = -1
9
9
 
10
+ # And encoding's superclass can always transport it since the
11
+ # class hierarchy is arranged e.g. Base64 < 7bit < 8bit < Binary.
10
12
  def self.can_transport?(enc)
11
- enc = Encodings.get_name(enc)
12
- if Encodings.defined? enc
13
- Encodings.get_encoding(enc).new.is_a? self
14
- else
15
- false
16
- end
13
+ enc && enc <= self
17
14
  end
18
15
 
16
+ # Override in subclasses to indicate that they can encode text
17
+ # that couldn't be directly transported, e.g. Base64 has 7bit output,
18
+ # but it can encode binary.
19
19
  def self.can_encode?(enc)
20
- can_transport? enc
20
+ can_transport? enc
21
21
  end
22
22
 
23
23
  def self.cost(str)
@@ -32,36 +32,45 @@ module Mail
32
32
  self::NAME
33
33
  end
34
34
 
35
- def self.get_best_compatible(source_encoding, str)
36
- if self.can_transport?(source_encoding) && self.compatible_input?(str)
35
+ def self.negotiate(message_encoding, source_encoding, str, allowed_encodings = nil)
36
+ message_encoding = Encodings.get_encoding(message_encoding) || Encodings.get_encoding('8bit')
37
+ source_encoding = Encodings.get_encoding(source_encoding)
38
+
39
+ if message_encoding && source_encoding && message_encoding.can_transport?(source_encoding) && source_encoding.compatible_input?(str)
37
40
  source_encoding
38
41
  else
39
- choices = Encodings.get_all.select do |enc|
40
- self.can_transport?(enc) && enc.can_encode?(source_encoding)
41
- end
42
+ renegotiate(message_encoding, source_encoding, str, allowed_encodings)
43
+ end
44
+ end
42
45
 
43
- best = nil
44
- best_cost = nil
46
+ def self.renegotiate(message_encoding, source_encoding, str, allowed_encodings = nil)
47
+ encodings = Encodings.get_all.select do |enc|
48
+ (allowed_encodings.nil? || allowed_encodings.include?(enc)) &&
49
+ message_encoding.can_transport?(enc) &&
50
+ enc.can_encode?(source_encoding)
51
+ end
45
52
 
46
- choices.each do |enc|
47
- # If the current choice cannot be transported safely,
48
- # give priority to other choices but allow it to be used as a fallback.
49
- this_cost = enc.cost(str) if enc.compatible_input?(str)
53
+ lowest_cost(str, encodings)
54
+ end
50
55
 
51
- if !best_cost || (this_cost && this_cost < best_cost)
52
- best_cost = this_cost
53
- best = enc
54
- elsif this_cost == best_cost
55
- best = enc if enc::PRIORITY < best::PRIORITY
56
- end
57
- end
56
+ def self.lowest_cost(str, encodings)
57
+ best = nil
58
+ best_cost = nil
58
59
 
59
- best
60
+ encodings.each do |enc|
61
+ # If the current choice cannot be transported safely, give priority
62
+ # to other choices but allow it to be used as a fallback.
63
+ this_cost = enc.cost(str) if enc.compatible_input?(str)
64
+
65
+ if !best_cost || (this_cost && this_cost < best_cost)
66
+ best_cost = this_cost
67
+ best = enc
68
+ elsif this_cost == best_cost
69
+ best = enc if enc::PRIORITY < best::PRIORITY
70
+ end
60
71
  end
61
- end
62
72
 
63
- def to_s
64
- self.class.to_s
73
+ best
65
74
  end
66
75
  end
67
76
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Mail
3
3
  module Encodings
4
- module UnixToUnix
4
+ class UnixToUnix < TransferEncoding
5
5
  NAME = "x-uuencode"
6
6
 
7
7
  def self.decode(str)
@@ -13,6 +13,8 @@ module Mail
13
13
  end
14
14
 
15
15
  Encodings.register(NAME, self)
16
+ Encodings.register("uuencode", self)
17
+ Encodings.register("x-uue", self)
16
18
  end
17
19
  end
18
20
  end
@@ -7,7 +7,6 @@ module Mail
7
7
  end
8
8
 
9
9
  module Encodings
10
-
11
10
  include Mail::Constants
12
11
  extend Mail::Utilities
13
12
 
@@ -19,7 +18,7 @@ module Mail
19
18
  #
20
19
  # Encodings.register "base64", Mail::Encodings::Base64
21
20
  def Encodings.register(name, cls)
22
- @transfer_encodings[get_name(name)] = cls
21
+ @transfer_encodings[get_name(name)] = cls
23
22
  end
24
23
 
25
24
  # Is the encoding we want defined?
@@ -27,8 +26,8 @@ module Mail
27
26
  # Example:
28
27
  #
29
28
  # Encodings.defined?(:base64) #=> true
30
- def Encodings.defined?( str )
31
- @transfer_encodings.include? get_name(str)
29
+ def Encodings.defined?(name)
30
+ @transfer_encodings.include? get_name(name)
32
31
  end
33
32
 
34
33
  # Gets a defined encoding type, QuotedPrintable or Base64 for now.
@@ -39,21 +38,21 @@ module Mail
39
38
  # Example:
40
39
  #
41
40
  # Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64
42
- def Encodings.get_encoding( str )
43
- @transfer_encodings[get_name(str)]
41
+ def Encodings.get_encoding(name)
42
+ @transfer_encodings[get_name(name)]
44
43
  end
45
44
 
46
45
  def Encodings.get_all
47
46
  @transfer_encodings.values
48
47
  end
49
48
 
50
- def Encodings.get_name(enc)
51
- underscoreize(enc).downcase
49
+ def Encodings.get_name(name)
50
+ underscoreize(name).downcase
52
51
  end
53
52
 
54
53
  def Encodings.transcode_charset(str, from_charset, to_charset = 'UTF-8')
55
54
  if from_charset
56
- RubyVer.transcode_charset str, from_charset, to_charset
55
+ Utilities.transcode_charset str, from_charset, to_charset
57
56
  else
58
57
  str
59
58
  end
@@ -66,8 +65,7 @@ module Mail
66
65
  # param_encode_language 'jp'
67
66
  # end
68
67
  #
69
- # The character set used for encoding will either be the value of $KCODE for
70
- # 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.
71
69
  #
72
70
  # Example:
73
71
  #
@@ -79,7 +77,7 @@ module Mail
79
77
  when str.ascii_only?
80
78
  str
81
79
  else
82
- RubyVer.param_encode(str)
80
+ Utilities.param_encode(str)
83
81
  end
84
82
  end
85
83
 
@@ -93,15 +91,15 @@ module Mail
93
91
  # str.encoding #=> 'ISO-8859-1' ## Only on Ruby 1.9
94
92
  # str #=> "This is fun"
95
93
  def Encodings.param_decode(str, encoding)
96
- RubyVer.param_decode(str, encoding)
94
+ Utilities.param_decode(str, encoding)
97
95
  end
98
96
 
99
97
  # Decodes or encodes a string as needed for either Base64 or QP encoding types in
100
98
  # the =?<encoding>?[QB]?<string>?=" format.
101
99
  #
102
100
  # The output type needs to be :decode to decode the input string or :encode to
103
- # encode the input string. The character set used for encoding will either be
104
- # the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in.
101
+ # encode the input string. The character set used for encoding will be the
102
+ # encoding on the string passed in.
105
103
  #
106
104
  # On encoding, will only send out Base64 encoded strings.
107
105
  def Encodings.decode_encode(str, output_type)
@@ -112,7 +110,7 @@ module Mail
112
110
  if str.ascii_only?
113
111
  str
114
112
  else
115
- Encodings.b_value_encode(str, find_encoding(str))
113
+ Encodings.b_value_encode(str, str.encoding)
116
114
  end
117
115
  end
118
116
  end
@@ -146,13 +144,8 @@ module Mail
146
144
  output
147
145
  elsif to_encoding
148
146
  begin
149
- if RUBY_VERSION >= '1.9'
150
- output.encode(to_encoding)
151
- else
152
- require 'iconv'
153
- Iconv.iconv(to_encoding, 'UTF-8', output).first
154
- end
155
- rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
147
+ output.encode(to_encoding)
148
+ rescue Errno::EINVAL
156
149
  # the 'from' parameter specifies a charset other than what the text
157
150
  # actually is...not much we can do in this case but just return the
158
151
  # unconverted text.
@@ -168,21 +161,21 @@ module Mail
168
161
 
169
162
  def Encodings.address_encode(address, charset = 'utf-8')
170
163
  if address.is_a?(Array)
171
- # loop back through for each element
172
164
  address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
173
- else
174
- # find any word boundary that is not ascii and encode it
175
- encode_non_usascii(address, charset) if address
165
+ elsif address
166
+ encode_non_usascii(address, charset)
176
167
  end
177
168
  end
178
169
 
179
170
  def Encodings.encode_non_usascii(address, charset)
180
171
  return address if address.ascii_only? or charset.nil?
181
- us_ascii = %Q{\x00-\x7f}
182
- # Encode any non usascii strings embedded inside of quotes
183
- address = address.gsub(/(".*?[^#{us_ascii}].*?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
172
+
173
+ # Encode all strings embedded inside of quotes
174
+ address = address.gsub(/("[^"]*[^\/]")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
175
+
184
176
  # Then loop through all remaining items and encode as needed
185
177
  tokens = address.split(/\s/)
178
+
186
179
  map_with_index(tokens) do |word, i|
187
180
  if word.ascii_only?
188
181
  word
@@ -203,12 +196,15 @@ module Mail
203
196
  #
204
197
  # Encodings.b_value_encode('This is あ string', 'UTF-8')
205
198
  # #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="
206
- def Encodings.b_value_encode(encoded_str, encoding = nil)
207
- return encoded_str if encoded_str.to_s.ascii_only?
208
- string, encoding = RubyVer.b_value_encode(encoded_str, encoding)
209
- map_lines(string) do |str|
210
- "=?#{encoding}?B?#{str.chomp}?="
211
- end.join(" ")
199
+ def Encodings.b_value_encode(string, encoding = nil)
200
+ if string.to_s.ascii_only?
201
+ string
202
+ else
203
+ Encodings.each_base64_chunk_byterange(string, 60).map do |chunk|
204
+ str, encoding = Utilities.b_value_encode(chunk, encoding)
205
+ "=?#{encoding}?B?#{str.chomp}?="
206
+ end.join(" ")
207
+ end
212
208
  end
213
209
 
214
210
  # Encode a string with Quoted-Printable Encoding and returns it ready to be inserted
@@ -220,7 +216,7 @@ module Mail
220
216
  # #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="
221
217
  def Encodings.q_value_encode(encoded_str, encoding = nil)
222
218
  return encoded_str if encoded_str.to_s.ascii_only?
223
- string, encoding = RubyVer.q_value_encode(encoded_str, encoding)
219
+ string, encoding = Utilities.q_value_encode(encoded_str, encoding)
224
220
  string.gsub!("=\r\n", '') # We already have limited the string to the length we want
225
221
  map_lines(string) do |str|
226
222
  "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
@@ -236,7 +232,7 @@ module Mail
236
232
  # Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
237
233
  # #=> 'This is あ string'
238
234
  def Encodings.b_value_decode(str)
239
- RubyVer.b_value_decode(str)
235
+ Utilities.b_value_decode(str)
240
236
  end
241
237
 
242
238
  # Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format
@@ -246,11 +242,7 @@ module Mail
246
242
  # Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
247
243
  # #=> 'This is あ string'
248
244
  def Encodings.q_value_decode(str)
249
- RubyVer.q_value_decode(str)
250
- end
251
-
252
- def Encodings.find_encoding(str)
253
- RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
245
+ Utilities.q_value_decode(str)
254
246
  end
255
247
 
256
248
  # Gets the encoding type (Q or B) from the string.
@@ -258,24 +250,23 @@ module Mail
258
250
  str[ENCODED_VALUE, 1]
259
251
  end
260
252
 
261
- # When the encoded string consists of multiple lines, lines with the same
262
- # encoding (Q or B) can be joined together.
253
+ # Split header line into proper encoded and unencoded parts.
263
254
  #
264
255
  # String has to be of the format =?<encoding>?[QB]?<string>?=
256
+ #
257
+ # Omit unencoded space after an encoded-word.
265
258
  def Encodings.collapse_adjacent_encodings(str)
266
259
  results = []
267
- previous_encoding = nil
260
+ last_encoded = nil # Track whether to preserve or drop whitespace
261
+
268
262
  lines = str.split(FULL_ENCODED_VALUE)
269
263
  lines.each_slice(2) do |unencoded, encoded|
270
- if encoded
271
- encoding = value_encoding_from_string(encoded)
272
- if encoding == previous_encoding && Utilities.blank?(unencoded)
273
- results.last << encoded
274
- else
275
- results << unencoded unless unencoded == EMPTY
276
- results << encoded
264
+ if last_encoded = encoded
265
+ if !Utilities.blank?(unencoded) || (!last_encoded && unencoded != EMPTY)
266
+ results << unencoded
277
267
  end
278
- previous_encoding = encoding
268
+
269
+ results << encoded
279
270
  else
280
271
  results << unencoded
281
272
  end
@@ -283,5 +274,41 @@ module Mail
283
274
 
284
275
  results
285
276
  end
277
+
278
+ # Partition the string into bounded-size chunks without splitting
279
+ # multibyte characters.
280
+ def Encodings.each_base64_chunk_byterange(str, max_bytesize_per_base64_chunk, &block)
281
+ raise "size per chunk must be multiple of 4" if (max_bytesize_per_base64_chunk % 4).nonzero?
282
+
283
+ if block_given?
284
+ max_bytesize = ((3 * max_bytesize_per_base64_chunk) / 4.0).floor
285
+ each_chunk_byterange(str, max_bytesize, &block)
286
+ else
287
+ enum_for :each_base64_chunk_byterange, str, max_bytesize_per_base64_chunk
288
+ end
289
+ end
290
+
291
+ # Partition the string into bounded-size chunks without splitting
292
+ # multibyte characters.
293
+ def Encodings.each_chunk_byterange(str, max_bytesize_per_chunk)
294
+ return enum_for(:each_chunk_byterange, str, max_bytesize_per_chunk) unless block_given?
295
+
296
+ offset = 0
297
+ chunksize = 0
298
+
299
+ str.each_char do |chr|
300
+ charsize = chr.bytesize
301
+
302
+ if chunksize + charsize > max_bytesize_per_chunk
303
+ yield Utilities.string_byteslice(str, offset, chunksize)
304
+ offset += chunksize
305
+ chunksize = charsize
306
+ else
307
+ chunksize += charsize
308
+ end
309
+ end
310
+
311
+ yield Utilities.string_byteslice(str, offset, chunksize)
312
+ end
286
313
  end
287
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 < StructuredField
13
-
14
- def initialize(*args)
15
- super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
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