mail 2.6.6 → 2.8.1

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 (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
@@ -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,226 +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
- if !str.end_with?("=") && str.length % 4 != 0
63
- str = str.ljust((str.length + 3) & ~3, "=")
64
- end
65
- str.unpack( 'm' ).first
66
- end
67
-
68
- def Ruby19.encode_base64(str)
69
- [str].pack( 'm' )
70
- end
71
-
72
- def Ruby19.has_constant?(klass, string)
73
- klass.const_defined?( string, false )
74
- end
75
-
76
- def Ruby19.get_constant(klass, string)
77
- klass.const_get( string )
78
- end
79
-
80
- def Ruby19.transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8)
81
- charset_encoder.encode(str.dup, from_encoding).encode(to_encoding, :undef => :replace, :invalid => :replace, :replace => '')
82
- end
83
-
84
- def Ruby19.b_value_encode(str, encoding = nil)
85
- encoding = str.encoding.to_s
86
- [Ruby19.encode_base64(str), encoding]
87
- end
88
-
89
- def Ruby19.b_value_decode(str)
90
- match = str.match(/\=\?(.+)?\?[Bb]\?(.*)\?\=/m)
91
- if match
92
- charset = match[1]
93
- str = Ruby19.decode_base64(match[2])
94
- str = charset_encoder.encode(str, charset)
95
- end
96
- decoded = str.encode(Encoding::UTF_8, :invalid => :replace, :replace => "")
97
- decoded.valid_encoding? ? decoded : decoded.encode(Encoding::UTF_16LE, :invalid => :replace, :replace => "").encode(Encoding::UTF_8)
98
- rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
99
- warn "Encoding conversion failed #{$!}"
100
- str.dup.force_encoding(Encoding::UTF_8)
101
- end
102
-
103
- def Ruby19.q_value_encode(str, encoding = nil)
104
- encoding = str.encoding.to_s
105
- [Encodings::QuotedPrintable.encode(str), encoding]
106
- end
107
-
108
- def Ruby19.q_value_decode(str)
109
- match = str.match(/\=\?(.+)?\?[Qq]\?(.*)\?\=/m)
110
- if match
111
- charset = match[1]
112
- string = match[2].gsub(/_/, '=20')
113
- # Remove trailing = if it exists in a Q encoding
114
- string = string.sub(/\=$/, '')
115
- str = Encodings::QuotedPrintable.decode(string)
116
- str = charset_encoder.encode(str, charset)
117
- # We assume that binary strings hold utf-8 directly to work around
118
- # jruby/jruby#829 which subtly changes String#encode semantics.
119
- str.force_encoding(Encoding::UTF_8) if str.encoding == Encoding::ASCII_8BIT
120
- end
121
- decoded = str.encode(Encoding::UTF_8, :invalid => :replace, :replace => "")
122
- decoded.valid_encoding? ? decoded : decoded.encode(Encoding::UTF_16LE, :invalid => :replace, :replace => "").encode(Encoding::UTF_8)
123
- rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
124
- warn "Encoding conversion failed #{$!}"
125
- str.dup.force_encoding(Encoding::UTF_8)
126
- end
127
-
128
- def Ruby19.param_decode(str, encoding)
129
- str = uri_parser.unescape(str)
130
- str = charset_encoder.encode(str, encoding) if encoding
131
- str
132
- end
133
-
134
- def Ruby19.param_encode(str)
135
- encoding = str.encoding.to_s.downcase
136
- language = Configuration.instance.param_encode_language
137
- "#{encoding}'#{language}'#{uri_parser.escape(str)}"
138
- end
139
-
140
- def Ruby19.uri_parser
141
- @uri_parser ||= URI::Parser.new
142
- end
143
-
144
- # Pick a Ruby encoding corresponding to the message charset. Most
145
- # charsets have a Ruby encoding, but some need manual aliasing here.
146
- #
147
- # TODO: add this as a test somewhere:
148
- # Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b}
149
- # Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b}
150
- def Ruby19.pick_encoding(charset)
151
- charset = charset.to_s
152
- encoding = case charset.downcase
153
-
154
- # ISO-8859-8-I etc. http://en.wikipedia.org/wiki/ISO-8859-8-I
155
- when /^iso[-_]?8859-(\d+)(-i)?$/
156
- "ISO-8859-#{$1}"
157
-
158
- # ISO-8859-15, ISO-2022-JP and alike
159
- when /^iso[-_]?(\d{4})-?(\w{1,2})$/
160
- "ISO-#{$1}-#{$2}"
161
-
162
- # "ISO-2022-JP-KDDI" and alike
163
- when /^iso[-_]?(\d{4})-?(\w{1,2})-?(\w*)$/
164
- "ISO-#{$1}-#{$2}-#{$3}"
165
-
166
- # UTF-8, UTF-32BE and alike
167
- when /^utf[\-_]?(\d{1,2})?(\w{1,2})$/
168
- "UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE')
169
-
170
- # Windows-1252 and alike
171
- when /^windows-?(.*)$/
172
- "Windows-#{$1}"
173
-
174
- when '8bit'
175
- Encoding::ASCII_8BIT
176
-
177
- # alternatives/misspellings of us-ascii seen in the wild
178
- when /^iso[-_]?646(-us)?$/, 'us=ascii'
179
- Encoding::ASCII
180
-
181
- # Microsoft-specific alias for MACROMAN
182
- when 'macintosh'
183
- Encoding::MACROMAN
184
-
185
- # Microsoft-specific alias for CP949 (Korean)
186
- when 'ks_c_5601-1987'
187
- Encoding::CP949
188
-
189
- # Wrongly written Shift_JIS (Japanese)
190
- when 'shift-jis'
191
- Encoding::Shift_JIS
192
-
193
- # GB2312 (Chinese charset) is a subset of GB18030 (its replacement)
194
- when 'gb2312'
195
- Encoding::GB18030
196
-
197
- when 'cp-850'
198
- Encoding::CP850
199
-
200
- when 'latin2'
201
- Encoding::ISO_8859_2
202
-
203
- else
204
- charset
205
- end
206
-
207
- convert_to_encoding(encoding)
208
- end
209
-
210
- class << self
211
- private
212
-
213
- def convert_to_encoding(encoding)
214
- if encoding.is_a?(Encoding)
215
- encoding
216
- else
217
- begin
218
- Encoding.find(encoding)
219
- rescue ArgumentError
220
- Encoding::BINARY
221
- end
222
- end
223
- end
224
- end
225
- end
226
- end