diff --git a/lib/mail/constants.rb b/lib/mail/constants.rb index 415f151a9..280ae5c97 100644 --- a/lib/mail/constants.rb +++ b/lib/mail/constants.rb @@ -42,6 +42,7 @@ module Constants HYPHEN = '-' COLON = ':' ASTERISK = '*' + DOUBLE_QUOTE = '"' CR = "\r" LF = "\n" CR_ENCODED = "=0D" diff --git a/lib/mail/parsers/address_lists_parser.rb b/lib/mail/parsers/address_lists_parser.rb index 07f881d56..3dcf9f52a 100644 --- a/lib/mail/parsers/address_lists_parser.rb +++ b/lib/mail/parsers/address_lists_parser.rb @@ -86,15 +86,15 @@ def parse(s) # Don't set the display name until the # address has actually started. This allows - # us to choose quoted_s version if it - # exists and always use the 'full' phrase + # us to always use the 'full' phrase # version. when :angle_addr_s - if qstr - address.display_name = qstr - qstr = nil - elsif phrase_e - address.display_name = s[phrase_s..phrase_e].strip + if phrase_e + phrase = s[phrase_s..phrase_e].strip + if phrase[0, 1] == DOUBLE_QUOTE && phrase[-1, 1] == DOUBLE_QUOTE + phrase = phrase[1..-2] + end + address.display_name = phrase phrase_e = phrase_s = nil end @@ -110,7 +110,7 @@ def parse(s) when :local_dot_atom_pre_comment_e local_dot_atom_pre_comment_e = p-1 when :local_quoted_string_e - address.local = '"' + qstr + '"' if address + address.local = DOUBLE_QUOTE + qstr + DOUBLE_QUOTE if address # obs_domain_list when :obs_domain_list_s then obs_domain_list_s = p diff --git a/lib/mail/utilities.rb b/lib/mail/utilities.rb index 670b79f6d..8b812f066 100644 --- a/lib/mail/utilities.rb +++ b/lib/mail/utilities.rb @@ -54,7 +54,7 @@ def quote_token( str ) # string = 'This is "a string"' # dquote(string #=> '"This is \"a string\"' def dquote( str ) - '"' + unquote(str).gsub(/[\\"]/n) {|s| '\\' + s } + '"' + DOUBLE_QUOTE + unquote(str).gsub(/[\\"]/n) {|s| '\\' + s } + DOUBLE_QUOTE end # Unwraps supplied string from inside double quotes and diff --git a/spec/mail/elements/address_spec.rb b/spec/mail/elements/address_spec.rb index fcd4b9e02..12d82defb 100644 --- a/spec/mail/elements/address_spec.rb +++ b/spec/mail/elements/address_spec.rb @@ -80,6 +80,26 @@ it "should decode the display name without calling #decoded first" do encoded = '=?ISO-8859-1?Q?Jan_Kr=FCtisch?= ' expect(Mail::Address.new(encoded).display_name).to eq 'Jan Krütisch' + + encoded = '=?ISO-8859-1?Q?Ja(n_Kr=FCt)isch?= ' + expect(Mail::Address.new(encoded).display_name).to eq 'Jaisch' + expect(Mail::Address.new(encoded).comments).to eq ['n_Kr=FCt'] + + encoded = '=?ISO-8859-1?Q?Jan_Kr=FCt(isc)h?= ' + expect(Mail::Address.new(encoded).display_name).to eq 'Jan Krüth' + expect(Mail::Address.new(encoded).comments).to eq ['isc'] + end + + it "should decode Q-encoded display name containing double quotes" do + encoded = '=?ISO-8859-1?Q?"Jan_Kr=FCtisch"?= ' + expect(Mail::Address.new(encoded).display_name).to eq '"Jan Krütisch"' + + encoded = '=?ISO-8859-1?Q?Jan_Kr=FCti"s"ch?= ' + expect(Mail::Address.new(encoded).display_name).to eq 'Jan Krüti"s"ch' + + encoded = '=?ISO-8859-1?Q?J(an)_Kr=FCti"s"ch?= ' + expect(Mail::Address.new(encoded).display_name).to eq 'J Krüti"s"ch' + expect(Mail::Address.new(encoded).comments).to eq ['an'] end it "should give back the local part" do @@ -669,7 +689,7 @@ expect(address.encoded).to eq '=?UTF-8?B?44G+44GR44KL?= ' end - it "should provide an encoded output for non us-ascii" do + it "should provide a decoded output for non us-ascii" do address = Mail::Address.new address.display_name = "まける" address.address = "mikel@test.lindsaar.net"