From 6740f441c4993259c69aa60a7d44ec8275941870 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Wed, 21 Nov 2012 05:37:22 +0000 Subject: [PATCH] fix non ASCII attachment filename encoding broken (MOJIBAKE) in receiving mail on Ruby 1.8 (#12399) git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@10852 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/mail_handler.rb | 19 ++++- .../gmail_with_attachment_iso-8859-1.eml | 26 +++++++ .../mail_handler/gmail_with_attachment_ja.eml | 20 +++++ ...thunderbird_with_attachment_iso-8859-1.eml | 34 +++++++++ .../thunderbird_with_attachment_ja.eml | 26 +++++++ test/unit/mail_handler_test.rb | 74 +++++++++++++++++++ 6 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/mail_handler/gmail_with_attachment_iso-8859-1.eml create mode 100644 test/fixtures/mail_handler/gmail_with_attachment_ja.eml create mode 100644 test/fixtures/mail_handler/thunderbird_with_attachment_iso-8859-1.eml create mode 100644 test/fixtures/mail_handler/thunderbird_with_attachment_ja.eml diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index b6cb2ac47..b87fbeda4 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -249,9 +249,26 @@ class MailHandler < ActionMailer::Base def add_attachments(obj) if email.attachments && email.attachments.any? email.attachments.each do |attachment| + filename = attachment.filename + unless filename.respond_to?(:encoding) + # try to reencode to utf8 manually with ruby1.8 + h = attachment.header['Content-Disposition'] + unless h.nil? + begin + if m = h.value.match(/filename\*[0-9\*]*=([^=']+)'/) + filename = Redmine::CodesetUtil.to_utf8(filename, m[1]) + elsif m = h.value.match(/filename=.*=\?([^\?]+)\?[BbQq]\?/) + # http://tools.ietf.org/html/rfc2047#section-4 + filename = Redmine::CodesetUtil.to_utf8(filename, m[1]) + end + rescue + # nop + end + end + end obj.attachments << Attachment.create(:container => obj, :file => attachment.decoded, - :filename => attachment.filename, + :filename => filename, :author => user, :content_type => attachment.mime_type) end diff --git a/test/fixtures/mail_handler/gmail_with_attachment_iso-8859-1.eml b/test/fixtures/mail_handler/gmail_with_attachment_iso-8859-1.eml new file mode 100644 index 000000000..4f1f6f347 --- /dev/null +++ b/test/fixtures/mail_handler/gmail_with_attachment_iso-8859-1.eml @@ -0,0 +1,26 @@ +Date: Tue, 20 Nov 2012 23:08:25 +0900 +Message-ID: +Subject: test +From: John Smith +To: redmine@somenet.foo +Content-Type: multipart/mixed; boundary=14dae93a13bf76ca5d04ceedc458 + +--14dae93a13bf76ca5d04ceedc458 +Content-Type: text/plain; charset=ISO-8859-1 + +test + +--14dae93a13bf76ca5d04ceedc458 +Content-Type: text/plain; charset=US-ASCII; + name="=?ISO-8859-1?B?xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tw=?= + =?ISO-8859-1?B?/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc?= + =?ISO-8859-1?B?/MTk1vbc/C50eHQ=?=" +Content-Disposition: attachment; + filename="=?ISO-8859-1?B?xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tw=?= + =?ISO-8859-1?B?/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc?= + =?ISO-8859-1?B?/MTk1vbc/C50eHQ=?=" +Content-Transfer-Encoding: base64 +X-Attachment-Id: f_h9r3mcjz0 + +dGVzdAo= +--14dae93a13bf76ca5d04ceedc458-- diff --git a/test/fixtures/mail_handler/gmail_with_attachment_ja.eml b/test/fixtures/mail_handler/gmail_with_attachment_ja.eml new file mode 100644 index 000000000..8d4e4f334 --- /dev/null +++ b/test/fixtures/mail_handler/gmail_with_attachment_ja.eml @@ -0,0 +1,20 @@ +Date: Mon, 19 Nov 2012 10:17:45 +0900 +Message-ID: +Subject: test +From: John Smith +To: redmine@somenet.foo +Content-Type: multipart/mixed; boundary=bcaec54ee4ea84f77904cecee22e + +--bcaec54ee4ea84f77904cecee22e +Content-Type: text/plain; charset=ISO-8859-1 + +test + +--bcaec54ee4ea84f77904cecee22e +Content-Type: text/plain; charset=US-ASCII; name="=?ISO-2022-JP?B?GyRCJUYlOSVIGyhCLnR4dA==?=" +Content-Disposition: attachment; filename="=?ISO-2022-JP?B?GyRCJUYlOSVIGyhCLnR4dA==?=" +Content-Transfer-Encoding: base64 +X-Attachment-Id: f_h9owndpv0 + +dGVzdAo= +--bcaec54ee4ea84f77904cecee22e-- diff --git a/test/fixtures/mail_handler/thunderbird_with_attachment_iso-8859-1.eml b/test/fixtures/mail_handler/thunderbird_with_attachment_iso-8859-1.eml new file mode 100644 index 000000000..89ad4a904 --- /dev/null +++ b/test/fixtures/mail_handler/thunderbird_with_attachment_iso-8859-1.eml @@ -0,0 +1,34 @@ +Message-ID: <50AB9546.7020800@gmail.com> +Date: Tue, 20 Nov 2012 23:35:50 +0900 +From: John Smith +User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc13 Thunderbird/3.1.10 +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: test +Content-Type: multipart/mixed; + boundary="------------050902080306030406090208" + +This is a multi-part message in MIME format. +--------------050902080306030406090208 +Content-Type: text/plain; charset=ISO-8859-1; format=flowed +Content-Transfer-Encoding: 7bit + +test + +--------------050902080306030406090208 +Content-Type: image/png; + name="=?ISO-8859-1?Q?=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4?= + =?ISO-8859-1?Q?=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6?= + =?ISO-8859-1?Q?=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6?= + =?ISO-8859-1?Q?=DC=FC=C4=E4=D6=F6=DC=FC=2Epng?=" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename*0*=ISO-8859-1''%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6; + filename*1*=%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC; + filename*2*=%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4; + filename*3*=%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%2E%70%6E%67 + +iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs4c6QAAAAlwSFlz +AAALEwAACxMBAJqcGAAAAAd0SU1FB9wLFA4fJhRKIUQAAAAUSURBVAjXY/z//z8DEmBiQAWk +8gHq9gMHP8uZWAAAAABJRU5ErkJggg== +--------------050902080306030406090208-- diff --git a/test/fixtures/mail_handler/thunderbird_with_attachment_ja.eml b/test/fixtures/mail_handler/thunderbird_with_attachment_ja.eml new file mode 100644 index 000000000..af7cbdf4c --- /dev/null +++ b/test/fixtures/mail_handler/thunderbird_with_attachment_ja.eml @@ -0,0 +1,26 @@ +Message-ID: <50AA00C6.4070108@gmail.com> +Date: Mon, 19 Nov 2012 18:49:58 +0900 +From: John Smith +User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.15) Gecko/20101027 Fedora/3.0.10-1.fc12 Lightning/1.0b1 Thunderbird/3.0.10 +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: test +Content-Type: multipart/mixed; + boundary="------------030104060902010800050907" + +This is a multi-part message in MIME format. +--------------030104060902010800050907 +Content-Type: text/plain; charset=ISO-2022-JP +Content-Transfer-Encoding: 7bit + +test + +--------------030104060902010800050907 +Content-Type: text/plain; + name="=?ISO-2022-JP?B?GyRCJUYlOSVIGyhCLnR4dA==?=" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename*=ISO-2022-JP''%1B%24%42%25%46%25%39%25%48%1B%28%42%2E%74%78%74 + +dGVzdAo= +--------------030104060902010800050907-- diff --git a/test/unit/mail_handler_test.rb b/test/unit/mail_handler_test.rb index 3a184b201..798d3b592 100644 --- a/test/unit/mail_handler_test.rb +++ b/test/unit/mail_handler_test.rb @@ -373,6 +373,80 @@ class MailHandlerTest < ActiveSupport::TestCase assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest end + def test_thunderbird_with_attachment_ja + issue = submit_email( + 'thunderbird_with_attachment_ja.eml', + :issue => {:project => 'ecookbook'} + ) + assert_kind_of Issue, issue + assert_equal 1, issue.attachments.size + ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" + ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) + attachment = issue.attachments.first + assert_equal ja, attachment.filename + assert_equal 5, attachment.filesize + assert File.exist?(attachment.diskfile) + assert_equal 5, File.size(attachment.diskfile) + assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest + end + + def test_gmail_with_attachment_ja + issue = submit_email( + 'gmail_with_attachment_ja.eml', + :issue => {:project => 'ecookbook'} + ) + assert_kind_of Issue, issue + assert_equal 1, issue.attachments.size + ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" + ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) + attachment = issue.attachments.first + assert_equal ja, attachment.filename + assert_equal 5, attachment.filesize + assert File.exist?(attachment.diskfile) + assert_equal 5, File.size(attachment.diskfile) + assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest + end + + def test_thunderbird_with_attachment_latin1 + issue = submit_email( + 'thunderbird_with_attachment_iso-8859-1.eml', + :issue => {:project => 'ecookbook'} + ) + assert_kind_of Issue, issue + assert_equal 1, issue.attachments.size + u = "" + u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) + u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" + u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) + 11.times { u << u1 } + attachment = issue.attachments.first + assert_equal "#{u}.png", attachment.filename + assert_equal 130, attachment.filesize + assert File.exist?(attachment.diskfile) + assert_equal 130, File.size(attachment.diskfile) + assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest + end + + def test_gmail_with_attachment_latin1 + issue = submit_email( + 'gmail_with_attachment_iso-8859-1.eml', + :issue => {:project => 'ecookbook'} + ) + assert_kind_of Issue, issue + assert_equal 1, issue.attachments.size + u = "" + u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) + u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" + u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) + 11.times { u << u1 } + attachment = issue.attachments.first + assert_equal "#{u}.txt", attachment.filename + assert_equal 5, attachment.filesize + assert File.exist?(attachment.diskfile) + assert_equal 5, File.size(attachment.diskfile) + assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest + end + def test_add_issue_with_iso_8859_1_subject issue = submit_email( 'subject_as_iso-8859-1.eml',