mail 2.5.5 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +170 -108
  4. data/lib/mail/attachments_list.rb +13 -10
  5. data/lib/mail/body.rb +105 -91
  6. data/lib/mail/check_delivery_params.rb +30 -22
  7. data/lib/mail/configuration.rb +3 -0
  8. data/lib/mail/constants.rb +79 -0
  9. data/lib/mail/elements/address.rb +118 -174
  10. data/lib/mail/elements/address_list.rb +16 -56
  11. data/lib/mail/elements/content_disposition_element.rb +12 -22
  12. data/lib/mail/elements/content_location_element.rb +9 -17
  13. data/lib/mail/elements/content_transfer_encoding_element.rb +8 -19
  14. data/lib/mail/elements/content_type_element.rb +20 -30
  15. data/lib/mail/elements/date_time_element.rb +10 -21
  16. data/lib/mail/elements/envelope_from_element.rb +23 -31
  17. data/lib/mail/elements/message_ids_element.rb +22 -20
  18. data/lib/mail/elements/mime_version_element.rb +10 -21
  19. data/lib/mail/elements/phrase_list.rb +13 -15
  20. data/lib/mail/elements/received_element.rb +26 -21
  21. data/lib/mail/elements.rb +1 -0
  22. data/lib/mail/encodings/7bit.rb +10 -14
  23. data/lib/mail/encodings/8bit.rb +5 -18
  24. data/lib/mail/encodings/base64.rb +15 -10
  25. data/lib/mail/encodings/binary.rb +4 -22
  26. data/lib/mail/encodings/identity.rb +24 -0
  27. data/lib/mail/encodings/quoted_printable.rb +13 -7
  28. data/lib/mail/encodings/transfer_encoding.rb +47 -28
  29. data/lib/mail/encodings/unix_to_unix.rb +20 -0
  30. data/lib/mail/encodings.rb +102 -93
  31. data/lib/mail/envelope.rb +12 -19
  32. data/lib/mail/field.rb +143 -71
  33. data/lib/mail/field_list.rb +73 -19
  34. data/lib/mail/fields/bcc_field.rb +42 -48
  35. data/lib/mail/fields/cc_field.rb +29 -50
  36. data/lib/mail/fields/comments_field.rb +28 -37
  37. data/lib/mail/fields/common_address_field.rb +170 -0
  38. data/lib/mail/fields/common_date_field.rb +58 -0
  39. data/lib/mail/fields/common_field.rb +77 -0
  40. data/lib/mail/fields/common_message_id_field.rb +42 -0
  41. data/lib/mail/fields/content_description_field.rb +8 -14
  42. data/lib/mail/fields/content_disposition_field.rb +20 -44
  43. data/lib/mail/fields/content_id_field.rb +25 -51
  44. data/lib/mail/fields/content_location_field.rb +12 -25
  45. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -36
  46. data/lib/mail/fields/content_type_field.rb +51 -80
  47. data/lib/mail/fields/date_field.rb +24 -52
  48. data/lib/mail/fields/from_field.rb +29 -50
  49. data/lib/mail/fields/in_reply_to_field.rb +39 -49
  50. data/lib/mail/fields/keywords_field.rb +19 -32
  51. data/lib/mail/fields/message_id_field.rb +26 -71
  52. data/lib/mail/fields/mime_version_field.rb +20 -30
  53. data/lib/mail/fields/named_structured_field.rb +11 -0
  54. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  55. data/lib/mail/fields/optional_field.rb +10 -7
  56. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +16 -13
  57. data/lib/mail/fields/received_field.rb +44 -57
  58. data/lib/mail/fields/references_field.rb +36 -49
  59. data/lib/mail/fields/reply_to_field.rb +29 -50
  60. data/lib/mail/fields/resent_bcc_field.rb +29 -50
  61. data/lib/mail/fields/resent_cc_field.rb +29 -50
  62. data/lib/mail/fields/resent_date_field.rb +6 -30
  63. data/lib/mail/fields/resent_from_field.rb +29 -50
  64. data/lib/mail/fields/resent_message_id_field.rb +6 -29
  65. data/lib/mail/fields/resent_sender_field.rb +28 -57
  66. data/lib/mail/fields/resent_to_field.rb +29 -50
  67. data/lib/mail/fields/return_path_field.rb +51 -55
  68. data/lib/mail/fields/sender_field.rb +35 -56
  69. data/lib/mail/fields/structured_field.rb +4 -30
  70. data/lib/mail/fields/subject_field.rb +10 -11
  71. data/lib/mail/fields/to_field.rb +29 -50
  72. data/lib/mail/fields/unstructured_field.rb +43 -51
  73. data/lib/mail/fields.rb +1 -0
  74. data/lib/mail/header.rb +78 -129
  75. data/lib/mail/indifferent_hash.rb +1 -0
  76. data/lib/mail/mail.rb +18 -11
  77. data/lib/mail/matchers/attachment_matchers.rb +44 -0
  78. data/lib/mail/matchers/has_sent_mail.rb +81 -4
  79. data/lib/mail/message.rb +142 -139
  80. data/lib/mail/multibyte/chars.rb +24 -180
  81. data/lib/mail/multibyte/unicode.rb +32 -27
  82. data/lib/mail/multibyte/utils.rb +27 -43
  83. data/lib/mail/multibyte.rb +56 -16
  84. data/lib/mail/network/delivery_methods/exim.rb +6 -4
  85. data/lib/mail/network/delivery_methods/file_delivery.rb +12 -10
  86. data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  87. data/lib/mail/network/delivery_methods/sendmail.rb +63 -21
  88. data/lib/mail/network/delivery_methods/smtp.rb +76 -50
  89. data/lib/mail/network/delivery_methods/smtp_connection.rb +4 -4
  90. data/lib/mail/network/delivery_methods/test_mailer.rb +5 -2
  91. data/lib/mail/network/retriever_methods/base.rb +9 -8
  92. data/lib/mail/network/retriever_methods/imap.rb +37 -18
  93. data/lib/mail/network/retriever_methods/pop3.rb +6 -3
  94. data/lib/mail/network/retriever_methods/test_retriever.rb +4 -2
  95. data/lib/mail/network.rb +2 -0
  96. data/lib/mail/parser_tools.rb +15 -0
  97. data/lib/mail/parsers/address_lists_parser.rb +33242 -0
  98. data/lib/mail/parsers/address_lists_parser.rl +179 -0
  99. data/lib/mail/parsers/content_disposition_parser.rb +901 -0
  100. data/lib/mail/parsers/content_disposition_parser.rl +89 -0
  101. data/lib/mail/parsers/content_location_parser.rb +822 -0
  102. data/lib/mail/parsers/content_location_parser.rl +78 -0
  103. data/lib/mail/parsers/content_transfer_encoding_parser.rb +522 -0
  104. data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
  105. data/lib/mail/parsers/content_type_parser.rb +1048 -0
  106. data/lib/mail/parsers/content_type_parser.rl +90 -0
  107. data/lib/mail/parsers/date_time_parser.rb +891 -0
  108. data/lib/mail/parsers/date_time_parser.rl +69 -0
  109. data/lib/mail/parsers/envelope_from_parser.rb +3675 -0
  110. data/lib/mail/parsers/envelope_from_parser.rl +89 -0
  111. data/lib/mail/parsers/message_ids_parser.rb +5161 -0
  112. data/lib/mail/parsers/message_ids_parser.rl +93 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +513 -0
  114. data/lib/mail/parsers/mime_version_parser.rl +68 -0
  115. data/lib/mail/parsers/phrase_lists_parser.rb +884 -0
  116. data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
  117. data/lib/mail/parsers/received_parser.rb +8782 -0
  118. data/lib/mail/parsers/received_parser.rl +91 -0
  119. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  120. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  121. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  122. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  123. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  124. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  125. data/lib/mail/parsers/rfc5322.rl +74 -0
  126. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  127. data/lib/mail/parsers/rfc5322_date_time.rl +37 -0
  128. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  129. data/lib/mail/parsers.rb +13 -0
  130. data/lib/mail/part.rb +11 -12
  131. data/lib/mail/parts_list.rb +90 -14
  132. data/lib/mail/smtp_envelope.rb +57 -0
  133. data/lib/mail/utilities.rb +415 -76
  134. data/lib/mail/values/unicode_tables.dat +0 -0
  135. data/lib/mail/version.rb +8 -15
  136. data/lib/mail/yaml.rb +30 -0
  137. data/lib/mail.rb +9 -32
  138. metadata +127 -79
  139. data/CHANGELOG.rdoc +0 -742
  140. data/CONTRIBUTING.md +0 -45
  141. data/Dependencies.txt +0 -3
  142. data/Gemfile +0 -32
  143. data/Rakefile +0 -21
  144. data/TODO.rdoc +0 -9
  145. data/lib/VERSION +0 -4
  146. data/lib/load_parsers.rb +0 -35
  147. data/lib/mail/core_extensions/nil.rb +0 -19
  148. data/lib/mail/core_extensions/object.rb +0 -13
  149. data/lib/mail/core_extensions/smtp.rb +0 -24
  150. data/lib/mail/core_extensions/string/access.rb +0 -145
  151. data/lib/mail/core_extensions/string/multibyte.rb +0 -78
  152. data/lib/mail/core_extensions/string.rb +0 -33
  153. data/lib/mail/fields/common/address_container.rb +0 -16
  154. data/lib/mail/fields/common/common_address.rb +0 -140
  155. data/lib/mail/fields/common/common_date.rb +0 -42
  156. data/lib/mail/fields/common/common_field.rb +0 -57
  157. data/lib/mail/fields/common/common_message_id.rb +0 -48
  158. data/lib/mail/multibyte/exceptions.rb +0 -8
  159. data/lib/mail/parsers/address_lists.rb +0 -64
  160. data/lib/mail/parsers/address_lists.treetop +0 -19
  161. data/lib/mail/parsers/content_disposition.rb +0 -535
  162. data/lib/mail/parsers/content_disposition.treetop +0 -46
  163. data/lib/mail/parsers/content_location.rb +0 -139
  164. data/lib/mail/parsers/content_location.treetop +0 -20
  165. data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
  166. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
  167. data/lib/mail/parsers/content_type.rb +0 -971
  168. data/lib/mail/parsers/content_type.treetop +0 -68
  169. data/lib/mail/parsers/date_time.rb +0 -114
  170. data/lib/mail/parsers/date_time.treetop +0 -11
  171. data/lib/mail/parsers/envelope_from.rb +0 -194
  172. data/lib/mail/parsers/envelope_from.treetop +0 -32
  173. data/lib/mail/parsers/message_ids.rb +0 -45
  174. data/lib/mail/parsers/message_ids.treetop +0 -15
  175. data/lib/mail/parsers/mime_version.rb +0 -144
  176. data/lib/mail/parsers/mime_version.treetop +0 -19
  177. data/lib/mail/parsers/phrase_lists.rb +0 -45
  178. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  179. data/lib/mail/parsers/received.rb +0 -71
  180. data/lib/mail/parsers/received.treetop +0 -11
  181. data/lib/mail/parsers/rfc2045.rb +0 -421
  182. data/lib/mail/parsers/rfc2045.treetop +0 -35
  183. data/lib/mail/parsers/rfc2822.rb +0 -5397
  184. data/lib/mail/parsers/rfc2822.treetop +0 -408
  185. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  186. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  187. data/lib/mail/patterns.rb +0 -35
  188. data/lib/mail/version_specific/ruby_1_8.rb +0 -119
  189. data/lib/mail/version_specific/ruby_1_9.rb +0 -147
  190. data/lib/tasks/corpus.rake +0 -125
  191. data/lib/tasks/treetop.rake +0 -10
@@ -1,35 +1,25 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/content_type_parser'
4
+
2
5
  module Mail
3
- class ContentTypeElement # :nodoc:
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::ContentTypeParser.new
9
- if tree = parser.parse(cleaned(string))
10
- @main_type = tree.main_type.text_value.downcase
11
- @sub_type = tree.sub_type.text_value.downcase
12
- @parameters = tree.parameters
13
- else
14
- raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason)
15
- end
16
- end
17
-
18
- def main_type
19
- @main_type
20
- end
21
-
22
- def sub_type
23
- @sub_type
6
+ class ContentTypeElement #:nodoc:
7
+ attr_reader :main_type, :sub_type, :parameters
8
+
9
+ def initialize(string)
10
+ content_type = Mail::Parsers::ContentTypeParser.parse(cleaned(string))
11
+ @main_type = content_type.main_type
12
+ @sub_type = content_type.sub_type
13
+ @parameters = content_type.parameters
24
14
  end
25
-
26
- def parameters
27
- @parameters
28
- end
29
-
30
- def cleaned(string)
31
- string =~ /(.+);\s*$/ ? $1 : string
32
- end
33
-
15
+
16
+ private
17
+ def cleaned(string)
18
+ if string =~ /;\s*$/
19
+ $`
20
+ else
21
+ string
22
+ end
23
+ end
34
24
  end
35
25
  end
@@ -1,26 +1,15 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/date_time_parser'
4
+
2
5
  module Mail
3
- class DateTimeElement # :nodoc:
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::DateTimeParser.new
9
- if tree = parser.parse(string)
10
- @date_string = tree.date.text_value
11
- @time_string = tree.time.text_value
12
- else
13
- raise Mail::Field::ParseError.new(DateTimeElement, string, parser.failure_reason)
14
- end
6
+ class DateTimeElement #:nodoc:
7
+ attr_reader :date_string, :time_string
8
+
9
+ def initialize(string)
10
+ date_time = Mail::Parsers::DateTimeParser.parse(string)
11
+ @date_string = date_time.date_string
12
+ @time_string = date_time.time_string
15
13
  end
16
-
17
- def date_string
18
- @date_string
19
- end
20
-
21
- def time_string
22
- @time_string
23
- end
24
-
25
14
  end
26
15
  end
@@ -1,47 +1,39 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/envelope_from_parser'
4
+ require 'date'
5
+
2
6
  module Mail
3
- class EnvelopeFromElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::EnvelopeFromParser.new
9
- if @tree = parser.parse(string)
10
- @address = tree.addr_spec.text_value.strip
11
- @date_time = ::DateTime.parse("#{tree.ctime_date.text_value}")
12
- else
13
- raise Mail::Field::ParseError.new(EnvelopeFromElement, string, parser.failure_reason)
14
- end
15
- end
16
-
17
- def tree
18
- @tree
19
- end
20
-
21
- def date_time
22
- @date_time
23
- end
24
-
25
- def address
26
- @address
7
+ class EnvelopeFromElement #:nodoc:
8
+ attr_reader :date_time, :address
9
+
10
+ def initialize(string)
11
+ envelope_from = Mail::Parsers::EnvelopeFromParser.parse(string)
12
+ @address = envelope_from.address
13
+ @date_time = ::DateTime.parse(envelope_from.ctime_date) if envelope_from.ctime_date
27
14
  end
28
-
15
+
29
16
  # RFC 4155:
30
17
  # a timestamp indicating the UTC date and time when the message
31
18
  # was originally received, conformant with the syntax of the
32
19
  # traditional UNIX 'ctime' output sans timezone (note that the
33
20
  # use of UTC precludes the need for a timezone indicator);
34
21
  def formatted_date_time
35
- if @date_time.respond_to?(:ctime)
36
- @date_time.ctime
37
- else
38
- @date_time.strftime '%a %b %e %T %Y'
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
39
28
  end
40
29
  end
41
30
 
42
31
  def to_s
43
- "#{@address} #{formatted_date_time}"
32
+ if date_time
33
+ "#{address} #{formatted_date_time}"
34
+ else
35
+ address
36
+ end
44
37
  end
45
-
46
38
  end
47
39
  end
@@ -1,29 +1,31 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/message_ids_parser'
4
+ require 'mail/utilities'
5
+
2
6
  module Mail
3
- class MessageIdsElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize(string)
8
- parser = Mail::MessageIdsParser.new
9
- if tree = parser.parse(string)
10
- @message_ids = tree.message_ids.map { |msg_id| clean_msg_id(msg_id.text_value) }
11
- else
12
- raise Mail::Field::ParseError.new(MessageIdsElement, string, parser.failure_reason)
13
- end
7
+ class MessageIdsElement #:nodoc:
8
+ def self.parse(string)
9
+ new(string).tap(&:message_ids)
14
10
  end
15
-
16
- def message_ids
17
- @message_ids
11
+
12
+ attr_reader :message_ids
13
+
14
+ def initialize(string)
15
+ @message_ids = parse(string)
18
16
  end
19
-
17
+
20
18
  def message_id
21
- @message_ids.first
22
- end
23
-
24
- def clean_msg_id( val )
25
- val =~ /.*<(.*)>.*/ ; $1
19
+ message_ids.first
26
20
  end
27
21
 
22
+ private
23
+ def parse(string)
24
+ if Utilities.blank? string
25
+ []
26
+ else
27
+ Mail::Parsers::MessageIdsParser.parse(string).message_ids
28
+ end
29
+ end
28
30
  end
29
31
  end
@@ -1,26 +1,15 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/mime_version_parser'
4
+
2
5
  module Mail
3
- class MimeVersionElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::MimeVersionParser.new
9
- if tree = parser.parse(string)
10
- @major = tree.major.text_value
11
- @minor = tree.minor.text_value
12
- else
13
- raise Mail::Field::ParseError.new(MimeVersionElement, string, parser.failure_reason)
14
- end
6
+ class MimeVersionElement #:nodoc:
7
+ attr_reader :major, :minor
8
+
9
+ def initialize(string)
10
+ mime_version = Mail::Parsers::MimeVersionParser.parse(string)
11
+ @major = mime_version.major
12
+ @minor = mime_version.minor
15
13
  end
16
-
17
- def major
18
- @major
19
- end
20
-
21
- def minor
22
- @minor
23
- end
24
-
25
14
  end
26
15
  end
@@ -1,21 +1,19 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/phrase_lists_parser'
4
+ require 'mail/utilities'
5
+
2
6
  module Mail
3
- class PhraseList
4
-
5
- include Mail::Utilities
6
-
7
+ class PhraseList #:nodoc:
8
+ attr_reader :phrases
9
+
7
10
  def initialize(string)
8
- parser = Mail::PhraseListsParser.new
9
- if tree = parser.parse(string)
10
- @phrases = tree.phrases
11
- else
12
- raise Mail::Field::ParseError.new(PhraseList, string, parser.failure_reason)
13
- end
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
14
17
  end
15
-
16
- def phrases
17
- @phrases.map { |p| unquote(p.text_value) }
18
- end
19
-
20
18
  end
21
19
  end
@@ -1,30 +1,35 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/received_parser'
4
+ require 'mail/utilities'
5
+ require 'date'
6
+
2
7
  module Mail
3
- class ReceivedElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::ReceivedParser.new
9
- if tree = parser.parse(string)
10
- @date_time = ::DateTime.parse("#{tree.date_time.date.text_value} #{tree.date_time.time.text_value}")
11
- @info = tree.name_val_list.text_value
8
+ class ReceivedElement #:nodoc:
9
+ attr_reader :info, :date_time
10
+
11
+ def initialize(string)
12
+ if Utilities.blank? string
13
+ @date_time = nil
14
+ @info = nil
12
15
  else
13
- raise Mail::Field::ParseError.new(ReceivedElement, string, parser.failure_reason)
16
+ received = Mail::Parsers::ReceivedParser.parse(string)
17
+ @date_time = datetime_for(received)
18
+ @info = received.info
14
19
  end
15
20
  end
16
-
17
- def date_time
18
- @date_time
19
- end
20
-
21
- def info
22
- @info
23
- end
24
-
21
+
25
22
  def to_s(*args)
26
- "#{@info}; #{@date_time.to_s(*args)}"
23
+ "#{info}; #{date_time.to_s(*args)}"
27
24
  end
28
-
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
29
34
  end
30
35
  end
data/lib/mail/elements.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Mail
2
3
  register_autoload :Address, 'mail/elements/address'
3
4
  register_autoload :AddressList, 'mail/elements/address_list'
@@ -1,31 +1,27 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/8bit'
3
4
 
4
5
  module Mail
5
6
  module Encodings
7
+ # 7bit and 8bit are equivalent. 7bit encoding is for text only.
6
8
  class SevenBit < EightBit
7
9
  NAME = '7bit'
8
-
9
10
  PRIORITY = 1
11
+ Encodings.register(NAME, self)
10
12
 
11
- # 7bit and 8bit operate the same
12
-
13
- # Decode the string
14
13
  def self.decode(str)
15
- super
14
+ ::Mail::Utilities.binary_unsafe_to_lf str
16
15
  end
17
-
18
- # Encode the string
16
+
19
17
  def self.encode(str)
20
- super
21
- end
22
-
23
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
- def self.cost(str)
25
- super
18
+ ::Mail::Utilities.binary_unsafe_to_crlf str
26
19
  end
27
20
 
28
- Encodings.register(NAME, self)
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
29
25
  end
30
26
  end
31
27
  end
@@ -1,31 +1,18 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/binary'
3
4
 
4
5
  module Mail
5
6
  module Encodings
6
7
  class EightBit < Binary
7
8
  NAME = '8bit'
8
-
9
9
  PRIORITY = 4
10
+ Encodings.register(NAME, self)
10
11
 
11
- # 8bit is an identiy encoding, meaning nothing to do
12
-
13
- # Decode the string
14
- def self.decode(str)
15
- str.to_lf
16
- end
17
-
18
- # Encode the string
19
- def self.encode(str)
20
- str.to_crlf
12
+ # Per RFC 2821 4.5.3.1, SMTP lines may not be longer than 1000 octets including the <CRLF>.
13
+ def self.compatible_input?(str)
14
+ !str.lines.find { |line| line.bytesize > 998 }
21
15
  end
22
-
23
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
- def self.cost(str)
25
- 1.0
26
- end
27
-
28
- Encodings.register(NAME, self)
29
16
  end
30
17
  end
31
18
  end
@@ -1,33 +1,38 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/7bit'
3
4
 
4
5
  module Mail
5
6
  module Encodings
7
+ # Base64 encoding handles binary content at the cost of 4 output bytes
8
+ # per input byte.
6
9
  class Base64 < SevenBit
7
10
  NAME = 'base64'
8
-
9
11
  PRIORITY = 3
10
-
12
+ Encodings.register(NAME, self)
13
+
11
14
  def self.can_encode?(enc)
12
15
  true
13
16
  end
14
17
 
15
- # Decode the string from Base64
16
18
  def self.decode(str)
17
- RubyVer.decode_base64( str )
19
+ Utilities.decode_base64(str)
18
20
  end
19
-
20
- # Encode the string to Base64
21
+
21
22
  def self.encode(str)
22
- RubyVer.encode_base64( str ).to_crlf
23
+ ::Mail::Utilities.binary_unsafe_to_crlf(Utilities.encode_base64(str))
23
24
  end
24
25
 
25
- # Base64 has a fixed cost, 4 bytes out per 3 bytes in
26
+ # 3 bytes in -> 4 bytes out
26
27
  def self.cost(str)
27
- 4.0/3
28
+ 4.0 / 3
28
29
  end
29
30
 
30
- Encodings.register(NAME, self)
31
+ # Ruby Base64 inserts newlines automatically, so it doesn't exceed
32
+ # SMTP line length limits.
33
+ def self.compatible_input?(str)
34
+ true
35
+ end
31
36
  end
32
37
  end
33
38
  end
@@ -1,31 +1,13 @@
1
1
  # encoding: utf-8
2
- require 'mail/encodings/transfer_encoding'
2
+ # frozen_string_literal: true
3
+ require 'mail/encodings/identity'
3
4
 
4
5
  module Mail
5
6
  module Encodings
6
- class Binary < TransferEncoding
7
+ class Binary < Identity
7
8
  NAME = 'binary'
8
-
9
9
  PRIORITY = 5
10
-
11
- # Binary is an identiy encoding, meaning nothing to do
12
-
13
- # Decode the string
14
- def self.decode(str)
15
- str
16
- end
17
-
18
- # Encode the string
19
- def self.encode(str)
20
- str
21
- end
22
-
23
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
- def self.cost(str)
25
- 1.0
26
- end
27
-
28
- Encodings.register(NAME, self)
10
+ Encodings.register(NAME, self)
29
11
  end
30
12
  end
31
13
  end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/encodings/transfer_encoding'
4
+
5
+ module Mail
6
+ module Encodings
7
+ # Identity encodings do no encoding/decoding and have a fixed cost:
8
+ # 1 byte in -> 1 byte out.
9
+ class Identity < TransferEncoding #:nodoc:
10
+ def self.decode(str)
11
+ str
12
+ end
13
+
14
+ def self.encode(str)
15
+ str
16
+ end
17
+
18
+ # 1 output byte per input byte.
19
+ def self.cost(str)
20
+ 1.0
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,36 +1,42 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/7bit'
3
4
 
4
5
  module Mail
5
6
  module Encodings
6
7
  class QuotedPrintable < SevenBit
7
8
  NAME='quoted-printable'
8
-
9
+
9
10
  PRIORITY = 2
10
11
 
11
- def self.can_encode?(str)
12
- EightBit.can_encode? str
12
+ def self.can_encode?(enc)
13
+ EightBit.can_encode? enc
13
14
  end
14
15
 
15
16
  # Decode the string from Quoted-Printable. Cope with hard line breaks
16
17
  # that were incorrectly encoded as hex instead of literal CRLF.
17
18
  def self.decode(str)
18
- str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first.to_lf
19
+ ::Mail::Utilities.to_lf ::Mail::Utilities.to_crlf(str).gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
19
20
  end
20
21
 
21
22
  def self.encode(str)
22
- [str.to_lf].pack("M").to_crlf
23
+ ::Mail::Utilities.to_crlf [::Mail::Utilities.to_lf(str)].pack("M")
23
24
  end
24
25
 
25
26
  def self.cost(str)
26
27
  # These bytes probably do not need encoding
27
28
  c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E")
28
- # Everything else turns into =XX where XX is a
29
+ # Everything else turns into =XX where XX is a
29
30
  # two digit hex number (taking 3 bytes)
30
31
  total = (str.bytesize - c)*3 + c
31
32
  total.to_f/str.bytesize
32
33
  end
33
-
34
+
35
+ # QP inserts newlines automatically and cannot violate the SMTP spec.
36
+ def self.compatible_input?(str)
37
+ true
38
+ end
39
+
34
40
  private
35
41
 
36
42
  Encodings.register(NAME, self)