diff options
-rw-r--r-- | actionmailer/CHANGELOG | 2 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/quoting.rb | 11 | ||||
-rw-r--r-- | actionmailer/test/quoting_test.rb | 48 |
3 files changed, 60 insertions, 1 deletions
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index d46727fe91..1fe104dcba 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Encode multibyte characters correctly #1894 + * Multipart messages specify a MIME-Version header automatically #2003 [John Long] * Add a unified render method to ActionMailer (delegates to ActionView::Base#render) diff --git a/actionmailer/lib/action_mailer/quoting.rb b/actionmailer/lib/action_mailer/quoting.rb index af4e8462a1..d6e04e4d83 100644 --- a/actionmailer/lib/action_mailer/quoting.rb +++ b/actionmailer/lib/action_mailer/quoting.rb @@ -3,10 +3,19 @@ module ActionMailer # Convert the given text into quoted printable format, with an instruction # that the text be eventually interpreted in the given charset. def quoted_printable(text, charset) - text = text.gsub( /[^a-z ]/i ) { "=%02x" % $&[0] }.gsub( / /, "_" ) + text = text.gsub( /[^a-z ]/i ) { quoted_printable_encode($&) }. + gsub( / /, "_" ) "=?#{charset}?Q?#{text}?=" end + # Convert the given character to quoted printable format, taking into + # account multi-byte characters (if executing with $KCODE="u", for instance) + def quoted_printable_encode(character) + result = "" + character.each_byte { |b| result << "=%02x" % b } + result + end + # A quick-and-dirty regexp for determining whether a string contains any # characters that need escaping. if !defined?(CHARS_NEEDING_QUOTING) diff --git a/actionmailer/test/quoting_test.rb b/actionmailer/test/quoting_test.rb new file mode 100644 index 0000000000..6291cd3db6 --- /dev/null +++ b/actionmailer/test/quoting_test.rb @@ -0,0 +1,48 @@ +$:.unshift(File.dirname(__FILE__) + "/../lib/") +$:.unshift(File.dirname(__FILE__) + "/../lib/action_mailer/vendor") + +require 'test/unit' +require 'tmail' +require 'tempfile' + +class QuotingTest < Test::Unit::TestCase + def test_quote_multibyte_chars + original = "\303\246 \303\270 and \303\245" + + result = execute_in_sandbox(<<-CODE) + $:.unshift(File.dirname(__FILE__) + "/../lib/") + $KCODE = 'u' + require 'jcode' + require 'action_mailer/quoting' + include ActionMailer::Quoting + quoted_printable(#{original.inspect}, "UTF-8") + CODE + + unquoted = TMail::Unquoter.unquote_and_convert_to(result, nil) + assert_equal unquoted, original + end + + private + + # This whole thing *could* be much simpler, but I don't think Tempfile, + # popen and others exist on all platforms (like Windows). + def execute_in_sandbox(code) + test_name = "#{File.dirname(__FILE__)}/am-quoting-test.#{$$}.rb" + res_name = "#{File.dirname(__FILE__)}/am-quoting-test.#{$$}.out" + + File.open(test_name, "w+") do |file| + file.write(<<-CODE) + block = Proc.new do + #{code} + end + puts block.call + CODE + end + + system("ruby #{test_name} > #{res_name}") or raise "could not run test in sandbox" + File.read(res_name) + ensure + File.delete(test_name) rescue nil + File.delete(res_name) rescue nil + end +end |