mail 2.6.4 → 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 (179) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +111 -118
  3. data/lib/mail/attachments_list.rb +11 -10
  4. data/lib/mail/body.rb +73 -84
  5. data/lib/mail/check_delivery_params.rb +54 -10
  6. data/lib/mail/configuration.rb +2 -0
  7. data/lib/mail/constants.rb +27 -5
  8. data/lib/mail/elements/address.rb +61 -50
  9. data/lib/mail/elements/address_list.rb +11 -19
  10. data/lib/mail/elements/content_disposition_element.rb +9 -16
  11. data/lib/mail/elements/content_location_element.rb +6 -11
  12. data/lib/mail/elements/content_transfer_encoding_element.rb +6 -11
  13. data/lib/mail/elements/content_type_element.rb +16 -23
  14. data/lib/mail/elements/date_time_element.rb +7 -15
  15. data/lib/mail/elements/envelope_from_element.rb +22 -23
  16. data/lib/mail/elements/message_ids_element.rb +18 -13
  17. data/lib/mail/elements/mime_version_element.rb +7 -15
  18. data/lib/mail/elements/phrase_list.rb +12 -10
  19. data/lib/mail/elements/received_element.rb +27 -19
  20. data/lib/mail/encodings/7bit.rb +9 -14
  21. data/lib/mail/encodings/8bit.rb +2 -21
  22. data/lib/mail/encodings/base64.rb +11 -12
  23. data/lib/mail/encodings/binary.rb +3 -22
  24. data/lib/mail/encodings/identity.rb +24 -0
  25. data/lib/mail/encodings/quoted_printable.rb +6 -6
  26. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  27. data/lib/mail/encodings/unix_to_unix.rb +3 -1
  28. data/lib/mail/encodings.rb +81 -54
  29. data/lib/mail/envelope.rb +11 -14
  30. data/lib/mail/field.rb +119 -98
  31. data/lib/mail/field_list.rb +60 -7
  32. data/lib/mail/fields/bcc_field.rb +34 -52
  33. data/lib/mail/fields/cc_field.rb +28 -49
  34. data/lib/mail/fields/comments_field.rb +27 -37
  35. data/lib/mail/fields/common_address_field.rb +170 -0
  36. data/lib/mail/fields/common_date_field.rb +58 -0
  37. data/lib/mail/fields/common_field.rb +77 -0
  38. data/lib/mail/fields/common_message_id_field.rb +42 -0
  39. data/lib/mail/fields/content_description_field.rb +7 -14
  40. data/lib/mail/fields/content_disposition_field.rb +13 -38
  41. data/lib/mail/fields/content_id_field.rb +24 -51
  42. data/lib/mail/fields/content_location_field.rb +11 -25
  43. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
  44. data/lib/mail/fields/content_type_field.rb +50 -80
  45. data/lib/mail/fields/date_field.rb +23 -52
  46. data/lib/mail/fields/from_field.rb +28 -49
  47. data/lib/mail/fields/in_reply_to_field.rb +38 -49
  48. data/lib/mail/fields/keywords_field.rb +18 -31
  49. data/lib/mail/fields/message_id_field.rb +25 -71
  50. data/lib/mail/fields/mime_version_field.rb +19 -30
  51. data/lib/mail/fields/named_structured_field.rb +11 -0
  52. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  53. data/lib/mail/fields/optional_field.rb +9 -7
  54. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +13 -11
  55. data/lib/mail/fields/received_field.rb +43 -57
  56. data/lib/mail/fields/references_field.rb +35 -49
  57. data/lib/mail/fields/reply_to_field.rb +28 -49
  58. data/lib/mail/fields/resent_bcc_field.rb +28 -49
  59. data/lib/mail/fields/resent_cc_field.rb +28 -49
  60. data/lib/mail/fields/resent_date_field.rb +5 -30
  61. data/lib/mail/fields/resent_from_field.rb +28 -49
  62. data/lib/mail/fields/resent_message_id_field.rb +5 -29
  63. data/lib/mail/fields/resent_sender_field.rb +27 -56
  64. data/lib/mail/fields/resent_to_field.rb +28 -49
  65. data/lib/mail/fields/return_path_field.rb +50 -54
  66. data/lib/mail/fields/sender_field.rb +34 -55
  67. data/lib/mail/fields/structured_field.rb +3 -30
  68. data/lib/mail/fields/subject_field.rb +9 -11
  69. data/lib/mail/fields/to_field.rb +28 -49
  70. data/lib/mail/fields/unstructured_field.rb +32 -47
  71. data/lib/mail/header.rb +71 -110
  72. data/lib/mail/mail.rb +2 -10
  73. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  74. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  75. data/lib/mail/message.rb +113 -117
  76. data/lib/mail/multibyte/chars.rb +23 -180
  77. data/lib/mail/multibyte/unicode.rb +10 -10
  78. data/lib/mail/multibyte/utils.rb +26 -43
  79. data/lib/mail/multibyte.rb +55 -16
  80. data/lib/mail/network/delivery_methods/exim.rb +8 -11
  81. data/lib/mail/network/delivery_methods/file_delivery.rb +13 -16
  82. data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  83. data/lib/mail/network/delivery_methods/sendmail.rb +32 -35
  84. data/lib/mail/network/delivery_methods/smtp.rb +76 -54
  85. data/lib/mail/network/delivery_methods/smtp_connection.rb +4 -9
  86. data/lib/mail/network/delivery_methods/test_mailer.rb +8 -9
  87. data/lib/mail/network/retriever_methods/base.rb +8 -8
  88. data/lib/mail/network/retriever_methods/imap.rb +20 -7
  89. data/lib/mail/network/retriever_methods/pop3.rb +5 -3
  90. data/lib/mail/network/retriever_methods/test_retriever.rb +3 -2
  91. data/lib/mail/network.rb +1 -0
  92. data/lib/mail/parser_tools.rb +15 -0
  93. data/lib/mail/parsers/address_lists_parser.rb +33225 -116
  94. data/lib/mail/parsers/address_lists_parser.rl +179 -0
  95. data/lib/mail/parsers/content_disposition_parser.rb +882 -49
  96. data/lib/mail/parsers/content_disposition_parser.rl +89 -0
  97. data/lib/mail/parsers/content_location_parser.rb +809 -23
  98. data/lib/mail/parsers/content_location_parser.rl +78 -0
  99. data/lib/mail/parsers/content_transfer_encoding_parser.rb +509 -21
  100. data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
  101. data/lib/mail/parsers/content_type_parser.rb +1037 -56
  102. data/lib/mail/parsers/content_type_parser.rl +90 -0
  103. data/lib/mail/parsers/date_time_parser.rb +877 -25
  104. data/lib/mail/parsers/date_time_parser.rl +69 -0
  105. data/lib/mail/parsers/envelope_from_parser.rb +3669 -40
  106. data/lib/mail/parsers/envelope_from_parser.rl +89 -0
  107. data/lib/mail/parsers/message_ids_parser.rb +5146 -25
  108. data/lib/mail/parsers/message_ids_parser.rl +93 -0
  109. data/lib/mail/parsers/mime_version_parser.rb +497 -26
  110. data/lib/mail/parsers/mime_version_parser.rl +68 -0
  111. data/lib/mail/parsers/phrase_lists_parser.rb +870 -22
  112. data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
  113. data/lib/mail/parsers/received_parser.rb +8776 -43
  114. data/lib/mail/parsers/received_parser.rl +91 -0
  115. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  116. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  117. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  118. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  119. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  120. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  121. data/lib/mail/parsers/rfc5322.rl +74 -0
  122. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  123. data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
  124. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  125. data/lib/mail/parsers.rb +11 -25
  126. data/lib/mail/part.rb +6 -10
  127. data/lib/mail/parts_list.rb +62 -6
  128. data/lib/mail/smtp_envelope.rb +57 -0
  129. data/lib/mail/utilities.rb +357 -74
  130. data/lib/mail/version.rb +2 -2
  131. data/lib/mail/yaml.rb +30 -0
  132. data/lib/mail.rb +5 -35
  133. metadata +111 -66
  134. data/CHANGELOG.rdoc +0 -787
  135. data/CONTRIBUTING.md +0 -60
  136. data/Dependencies.txt +0 -2
  137. data/Gemfile +0 -11
  138. data/Rakefile +0 -29
  139. data/TODO.rdoc +0 -9
  140. data/lib/mail/core_extensions/smtp.rb +0 -25
  141. data/lib/mail/core_extensions/string/access.rb +0 -146
  142. data/lib/mail/core_extensions/string/multibyte.rb +0 -79
  143. data/lib/mail/core_extensions/string.rb +0 -21
  144. data/lib/mail/fields/common/address_container.rb +0 -17
  145. data/lib/mail/fields/common/common_address.rb +0 -136
  146. data/lib/mail/fields/common/common_date.rb +0 -36
  147. data/lib/mail/fields/common/common_field.rb +0 -61
  148. data/lib/mail/fields/common/common_message_id.rb +0 -49
  149. data/lib/mail/multibyte/exceptions.rb +0 -9
  150. data/lib/mail/parsers/ragel/common.rl +0 -185
  151. data/lib/mail/parsers/ragel/parser_info.rb +0 -61
  152. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
  153. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
  154. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
  155. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
  156. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
  157. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
  158. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
  159. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
  160. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
  161. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
  162. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
  163. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
  164. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
  165. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
  166. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
  167. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
  168. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
  169. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
  170. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
  171. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
  172. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
  173. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
  174. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
  175. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
  176. data/lib/mail/parsers/ragel/ruby.rb +0 -40
  177. data/lib/mail/parsers/ragel.rb +0 -18
  178. data/lib/mail/version_specific/ruby_1_8.rb +0 -126
  179. data/lib/mail/version_specific/ruby_1_9.rb +0 -223
@@ -1,37 +0,0 @@
1
- %%{
2
- machine received;
3
-
4
- include rb_actions "rb_actions.rl";
5
- include common "../../common.rl";
6
-
7
- getkey data_unpacked[p];
8
-
9
- main := received;
10
- }%%
11
-
12
- module Mail
13
- module Parsers
14
- module Ragel
15
- module ReceivedMachine
16
- %%write data;
17
-
18
- def self.parse(data)
19
- p = 0
20
- eof = data.length
21
- stack = []
22
-
23
- actions = []
24
- data_unpacked = data.bytes.to_a
25
- %%write init;
26
- %%write exec;
27
-
28
- if p == eof && cs >= %%{ write first_final; }%%
29
- return actions, nil
30
- else
31
- return [], "Only able to parse up to #{data[0..p]}"
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,37 +0,0 @@
1
- %%{
2
- machine <%= parser_name %>;
3
-
4
- include rb_actions "rb_actions.rl";
5
- include common "../../common.rl";
6
-
7
- getkey data_unpacked[p];
8
-
9
- main := <%= parser_name %>;
10
- }%%
11
-
12
- module Mail
13
- module Parsers
14
- module Ragel
15
- module <%= parser_name_cc %>
16
- %%write data;
17
-
18
- def self.parse(data)
19
- p = 0
20
- eof = data.length
21
- stack = []
22
-
23
- actions = []
24
- data_unpacked = data.bytes.to_a
25
- %%write init;
26
- %%write exec;
27
-
28
- if p == eof && cs >= %%{ write first_final; }%%
29
- return actions, nil
30
- else
31
- return [], "Only able to parse up to #{data[0..p]}"
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,40 +0,0 @@
1
- module Mail
2
- module Parsers
3
- module Ragel
4
- module Ruby
5
- def self.silence_warnings
6
- old, $VERBOSE = $VERBOSE, nil
7
- yield
8
- ensure
9
- $VERBOSE = old
10
- end
11
-
12
- # Ragel-generated parsers give a lot of warnings
13
- # and may cause logs to balloon in size
14
- silence_warnings do
15
- Mail::Parsers::Ragel::FIELD_PARSERS.each do |field_parser|
16
- require "mail/parsers/ragel/ruby/machines/#{field_parser}_machine"
17
- end
18
- end
19
-
20
- MACHINE_LIST = {
21
- :address_lists => AddressListsMachine,
22
- :phrase_lists => PhraseListsMachine,
23
- :date_time => DateTimeMachine,
24
- :received => ReceivedMachine,
25
- :message_ids => MessageIdsMachine,
26
- :envelope_from => EnvelopeFromMachine,
27
- :mime_version => MimeVersionMachine,
28
- :content_type => ContentTypeMachine,
29
- :content_disposition => ContentDispositionMachine,
30
- :content_transfer_encoding => ContentTransferEncodingMachine,
31
- :content_location => ContentLocationMachine
32
- }
33
-
34
- def self.parse(machine, string)
35
- MACHINE_LIST[machine].parse(string)
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mail
3
- module Parsers
4
- module Ragel
5
- require 'mail/parsers/ragel/parser_info'
6
- require "mail/parsers/ragel/ruby"
7
-
8
- def self.parse(machine, string)
9
- @machine_module ||= Ruby
10
- @machine_module.parse(machine, string)
11
- end
12
-
13
- def self.machine_module=(m)
14
- @machine_module = m
15
- end
16
- end
17
- end
18
- end
@@ -1,126 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- module Mail
5
- class Ruby18
6
- require 'base64'
7
- require 'iconv'
8
-
9
- # Escapes any parenthesis in a string that are unescaped. This can't
10
- # use the Ruby 1.9.1 regexp feature of negative look behind so we have
11
- # to do two replacement, first unescape everything, then re-escape it
12
- def Ruby18.escape_paren( str )
13
- re = /\\\)/
14
- str = str.gsub(re) { |s| ')'}
15
- re = /\\\(/
16
- str = str.gsub(re) { |s| '('}
17
- re = /([\(\)])/ # Only match unescaped parens
18
- str.gsub(re) { |s| '\\' + s }
19
- end
20
-
21
- def Ruby18.paren( str )
22
- str = $1 if str =~ /^\((.*)?\)$/
23
- str = escape_paren( str )
24
- '(' + str + ')'
25
- end
26
-
27
- def Ruby18.escape_bracket( str )
28
- re = /\\\>/
29
- str = str.gsub(re) { |s| '>'}
30
- re = /\\\</
31
- str = str.gsub(re) { |s| '<'}
32
- re = /([\<\>])/ # Only match unescaped parens
33
- str.gsub(re) { |s| '\\' + s }
34
- end
35
-
36
- def Ruby18.bracket( str )
37
- str = $1 if str =~ /^\<(.*)?\>$/
38
- str = escape_bracket( str )
39
- '<' + str + '>'
40
- end
41
-
42
- def Ruby18.decode_base64(str)
43
- Base64.decode64(str) if str
44
- end
45
-
46
- def Ruby18.encode_base64(str)
47
- Base64.encode64(str)
48
- end
49
-
50
- def Ruby18.has_constant?(klass, string)
51
- klass.constants.include?( string )
52
- end
53
-
54
- def Ruby18.get_constant(klass, string)
55
- klass.const_get( string )
56
- end
57
-
58
- def Ruby18.transcode_charset(str, from_encoding, to_encoding = 'UTF-8')
59
- Iconv.conv("#{normalize_iconv_charset_encoding(to_encoding)}//IGNORE", normalize_iconv_charset_encoding(from_encoding), str)
60
- end
61
-
62
- def Ruby18.b_value_encode(str, encoding)
63
- # Ruby 1.8 requires an encoding to work
64
- raise ArgumentError, "Must supply an encoding" if encoding.nil?
65
- encoding = encoding.to_s.upcase.gsub('_', '-')
66
- [Encodings::Base64.encode(str), normalize_iconv_charset_encoding(encoding)]
67
- end
68
-
69
- def Ruby18.b_value_decode(str)
70
- match = str.match(/\=\?(.+)?\?[Bb]\?(.*)\?\=/m)
71
- if match
72
- encoding = match[1]
73
- str = Ruby18.decode_base64(match[2])
74
- str = transcode_charset(str, encoding)
75
- end
76
- str
77
- end
78
-
79
- def Ruby18.q_value_encode(str, encoding)
80
- # Ruby 1.8 requires an encoding to work
81
- raise ArgumentError, "Must supply an encoding" if encoding.nil?
82
- encoding = encoding.to_s.upcase.gsub('_', '-')
83
- [Encodings::QuotedPrintable.encode(str), encoding]
84
- end
85
-
86
- def Ruby18.q_value_decode(str)
87
- match = str.match(/\=\?(.+)?\?[Qq]\?(.*)\?\=/m)
88
- if match
89
- encoding = match[1]
90
- string = match[2].gsub(/_/, '=20')
91
- # Remove trailing = if it exists in a Q encoding
92
- string = string.sub(/\=$/, '')
93
- str = Encodings::QuotedPrintable.decode(string)
94
- str = transcode_charset(str, encoding)
95
- end
96
- str
97
- end
98
-
99
- def Ruby18.param_decode(str, encoding)
100
- URI.unescape(str)
101
- end
102
-
103
- def Ruby18.param_encode(str)
104
- encoding = $KCODE.to_s.downcase
105
- language = Configuration.instance.param_encode_language
106
- "#{encoding}'#{language}'#{URI.escape(str)}"
107
- end
108
-
109
- private
110
-
111
- def Ruby18.normalize_iconv_charset_encoding(encoding)
112
- case encoding.upcase
113
- when 'UTF8', 'UTF_8'
114
- 'UTF-8'
115
- when 'UTF16', 'UTF-16'
116
- 'UTF-16BE'
117
- when 'UTF32', 'UTF-32'
118
- 'UTF-32BE'
119
- when 'KS_C_5601-1987'
120
- 'CP949'
121
- else
122
- encoding
123
- end
124
- end
125
- end
126
- end
@@ -1,223 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- module Mail
5
- class Ruby19
6
- class StrictCharsetEncoder
7
- def encode(string, charset)
8
- string.force_encoding(Mail::Ruby19.pick_encoding(charset))
9
- end
10
- end
11
-
12
- class BestEffortCharsetEncoder
13
- def encode(string, charset)
14
- string.force_encoding(pick_encoding(charset))
15
- end
16
-
17
- private
18
-
19
- def pick_encoding(charset)
20
- charset = case charset
21
- when /ansi_x3.110-1983/
22
- 'ISO-8859-1'
23
- when /Windows-?1258/i # Windows-1258 is similar to 1252
24
- "Windows-1252"
25
- else
26
- charset
27
- end
28
- Mail::Ruby19.pick_encoding(charset)
29
- end
30
- end
31
-
32
- class << self
33
- attr_accessor :charset_encoder
34
- end
35
- self.charset_encoder = StrictCharsetEncoder.new
36
-
37
- # Escapes any parenthesis in a string that are unescaped this uses
38
- # a Ruby 1.9.1 regexp feature of negative look behind
39
- def Ruby19.escape_paren( str )
40
- re = /(?<!\\)([\(\)])/ # Only match unescaped parens
41
- str.gsub(re) { |s| '\\' + s }
42
- end
43
-
44
- def Ruby19.paren( str )
45
- str = $1 if str =~ /^\((.*)?\)$/
46
- str = escape_paren( str )
47
- '(' + str + ')'
48
- end
49
-
50
- def Ruby19.escape_bracket( str )
51
- re = /(?<!\\)([\<\>])/ # Only match unescaped brackets
52
- str.gsub(re) { |s| '\\' + s }
53
- end
54
-
55
- def Ruby19.bracket( str )
56
- str = $1 if str =~ /^\<(.*)?\>$/
57
- str = escape_bracket( str )
58
- '<' + str + '>'
59
- end
60
-
61
- def Ruby19.decode_base64(str)
62
- str.unpack( 'm' ).first
63
- end
64
-
65
- def Ruby19.encode_base64(str)
66
- [str].pack( 'm' )
67
- end
68
-
69
- def Ruby19.has_constant?(klass, string)
70
- klass.const_defined?( string, false )
71
- end
72
-
73
- def Ruby19.get_constant(klass, string)
74
- klass.const_get( string )
75
- end
76
-
77
- def Ruby19.transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8)
78
- charset_encoder.encode(str.dup, from_encoding).encode(to_encoding, :undef => :replace, :invalid => :replace, :replace => '')
79
- end
80
-
81
- def Ruby19.b_value_encode(str, encoding = nil)
82
- encoding = str.encoding.to_s
83
- [Ruby19.encode_base64(str), encoding]
84
- end
85
-
86
- def Ruby19.b_value_decode(str)
87
- match = str.match(/\=\?(.+)?\?[Bb]\?(.*)\?\=/m)
88
- if match
89
- charset = match[1]
90
- str = Ruby19.decode_base64(match[2])
91
- str = charset_encoder.encode(str, charset)
92
- end
93
- decoded = str.encode(Encoding::UTF_8, :invalid => :replace, :replace => "")
94
- decoded.valid_encoding? ? decoded : decoded.encode(Encoding::UTF_16LE, :invalid => :replace, :replace => "").encode(Encoding::UTF_8)
95
- rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
96
- warn "Encoding conversion failed #{$!}"
97
- str.dup.force_encoding(Encoding::UTF_8)
98
- end
99
-
100
- def Ruby19.q_value_encode(str, encoding = nil)
101
- encoding = str.encoding.to_s
102
- [Encodings::QuotedPrintable.encode(str), encoding]
103
- end
104
-
105
- def Ruby19.q_value_decode(str)
106
- match = str.match(/\=\?(.+)?\?[Qq]\?(.*)\?\=/m)
107
- if match
108
- charset = match[1]
109
- string = match[2].gsub(/_/, '=20')
110
- # Remove trailing = if it exists in a Q encoding
111
- string = string.sub(/\=$/, '')
112
- str = Encodings::QuotedPrintable.decode(string)
113
- str = charset_encoder.encode(str, charset)
114
- # We assume that binary strings hold utf-8 directly to work around
115
- # jruby/jruby#829 which subtly changes String#encode semantics.
116
- str.force_encoding(Encoding::UTF_8) if str.encoding == Encoding::ASCII_8BIT
117
- end
118
- decoded = str.encode(Encoding::UTF_8, :invalid => :replace, :replace => "")
119
- decoded.valid_encoding? ? decoded : decoded.encode(Encoding::UTF_16LE, :invalid => :replace, :replace => "").encode(Encoding::UTF_8)
120
- rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
121
- warn "Encoding conversion failed #{$!}"
122
- str.dup.force_encoding(Encoding::UTF_8)
123
- end
124
-
125
- def Ruby19.param_decode(str, encoding)
126
- str = uri_parser.unescape(str)
127
- str = charset_encoder.encode(str, encoding) if encoding
128
- str
129
- end
130
-
131
- def Ruby19.param_encode(str)
132
- encoding = str.encoding.to_s.downcase
133
- language = Configuration.instance.param_encode_language
134
- "#{encoding}'#{language}'#{uri_parser.escape(str)}"
135
- end
136
-
137
- def Ruby19.uri_parser
138
- @uri_parser ||= URI::Parser.new
139
- end
140
-
141
- # Pick a Ruby encoding corresponding to the message charset. Most
142
- # charsets have a Ruby encoding, but some need manual aliasing here.
143
- #
144
- # TODO: add this as a test somewhere:
145
- # Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b}
146
- # Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b}
147
- def Ruby19.pick_encoding(charset)
148
- charset = charset.to_s
149
- encoding = case charset.downcase
150
-
151
- # ISO-8859-8-I etc. http://en.wikipedia.org/wiki/ISO-8859-8-I
152
- when /^iso[-_]?8859-(\d+)(-i)?$/
153
- "ISO-8859-#{$1}"
154
-
155
- # ISO-8859-15, ISO-2022-JP and alike
156
- when /^iso[-_]?(\d{4})-?(\w{1,2})$/
157
- "ISO-#{$1}-#{$2}"
158
-
159
- # "ISO-2022-JP-KDDI" and alike
160
- when /^iso[-_]?(\d{4})-?(\w{1,2})-?(\w*)$/
161
- "ISO-#{$1}-#{$2}-#{$3}"
162
-
163
- # UTF-8, UTF-32BE and alike
164
- when /^utf[\-_]?(\d{1,2})?(\w{1,2})$/
165
- "UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE')
166
-
167
- # Windows-1252 and alike
168
- when /^windows-?(.*)$/
169
- "Windows-#{$1}"
170
-
171
- when '8bit'
172
- Encoding::ASCII_8BIT
173
-
174
- # alternatives/misspellings of us-ascii seen in the wild
175
- when /^iso[-_]?646(-us)?$/, 'us=ascii'
176
- Encoding::ASCII
177
-
178
- # Microsoft-specific alias for MACROMAN
179
- when 'macintosh'
180
- Encoding::MACROMAN
181
-
182
- # Microsoft-specific alias for CP949 (Korean)
183
- when 'ks_c_5601-1987'
184
- Encoding::CP949
185
-
186
- # Wrongly written Shift_JIS (Japanese)
187
- when 'shift-jis'
188
- Encoding::Shift_JIS
189
-
190
- # GB2312 (Chinese charset) is a subset of GB18030 (its replacement)
191
- when 'gb2312'
192
- Encoding::GB18030
193
-
194
- when 'cp-850'
195
- Encoding::CP850
196
-
197
- when 'latin2'
198
- Encoding::ISO_8859_2
199
-
200
- else
201
- charset
202
- end
203
-
204
- convert_to_encoding(encoding)
205
- end
206
-
207
- class << self
208
- private
209
-
210
- def convert_to_encoding(encoding)
211
- if encoding.is_a?(Encoding)
212
- encoding
213
- else
214
- begin
215
- Encoding.find(encoding)
216
- rescue ArgumentError
217
- Encoding::BINARY
218
- end
219
- end
220
- end
221
- end
222
- end
223
- end