Skip to content

Apply patches from kuroda/iso-2022-jp #534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/mail.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module Mail # :doc:
require 'mail/patterns'
require 'mail/utilities'
require 'mail/configuration'
require 'mail/preprocessor'

@@autoloads = {}
def self.register_autoload(name, path)
Expand Down
3 changes: 3 additions & 0 deletions lib/mail/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ module Mail
class Body

def initialize(string = '')
if string.respond_to?(:encoding) && string.encoding.to_s.downcase == 'iso-2022-jp'
string.force_encoding('US-ASCII')
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we converting the raw body from iso-2022-jp to us-ascii?

@boundary = nil
@preamble = nil
@epilogue = nil
Expand Down
4 changes: 4 additions & 0 deletions lib/mail/encodings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ module Mail
class UnknownEncodingType < StandardError #:nodoc:
end

# Raised when attempting to convert non-UTF-8 characters with NKF
class InvalidEncodingError < StandardError #:nodoc:
end

module Encodings

include Mail::Patterns
Expand Down
1 change: 1 addition & 0 deletions lib/mail/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class SyntaxError < FieldError #:nodoc:
#
# Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
def initialize(name, value = nil, charset = 'utf-8')
value = RubyVer.preprocess(charset, value)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should move this into the cases below? name may contain "name: value"

case
when name =~ /:/ # Field.new("field-name: field data")
charset = value unless value.blank?
Expand Down
12 changes: 0 additions & 12 deletions lib/mail/fields/bcc_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,9 @@ class BccField < StructuredField
FIELD_NAME = 'bcc'
CAPITALIZED_FIELD = 'Bcc'

def initialize(value = '', charset = 'utf-8')
@charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

# Bcc field should never be :encoded
def encoded
''
end

def decoded
do_decode
end

end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/cc_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,5 @@ class CcField < StructuredField
FIELD_NAME = 'cc'
CAPITALIZED_FIELD = 'Cc'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
55 changes: 43 additions & 12 deletions lib/mail/fields/common/common_address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,45 @@

module Mail
module CommonAddress # :nodoc:


def initialize(value = nil, charset = 'utf-8')
if charset.to_s.downcase == 'iso-2022-jp'
if value.kind_of?(Array)
value = value.map { |e| encode_with_iso_2022_jp(e) }
else
value = encode_with_iso_2022_jp(value)
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Special-casing multiple code paths based on charset is a good sign that we should extract the charset-specific coding/decoding operations.

I suggest introducing something like a CharsetCodec that's responsible for them.

CharsetCodec.find(charset) #=> ISO2022JPCodec

class CharsetCodec
  @codecs = Hash.new { |h, k| h[k] = CharsetCodec.new }
  def self.find(name) @codecs[name] end
  def self.register(name, codec) @codecs[name] = codec end

  def encode_address(value)
    value
  end

  def remap_characters(value)
    value
  end
end

class ISO2022JPCodec < CharsetCodec
  def encode_address(value)
    if value.kind_of?(Array)
      value.map { |e| encode_address e }
    elsif value =~ / <[\x00-\x7f]*>\z/
      encode value
    else
      value
    end
  end

  def remap_characters(value)
    # Mail::Preprocessor.process goes here
    value.gsub(REMAP_MATCH) { |c| REMAP[c] }
  end

  def encode(string)
    RubyVer.encode_with_iso_2022_jp string
  end
end

CharsetCodec.register 'iso-2022-jp', ISO2022JPCodec.new

self.charset = charset
super(self.class.const_get('CAPITALIZED_FIELD'), strip_field(self.class.const_get('FIELD_NAME'), value), charset)
self.parse
self
end

def encoded
do_encode(self.class.const_get('CAPITALIZED_FIELD'))
end

def decoded
do_decode
end

def parse(val = value)
unless val.blank?
@tree = AddressList.new(encode_if_needed(val))
else
nil
end
end

def charset
@charset
end

def encode_if_needed(val)
Encodings.address_encode(val, charset)
end

# Allows you to iterate through each address object in the syntax tree
def each
tree.addresses.each do |address|
Expand All @@ -38,19 +60,19 @@ def formatted
list = tree.addresses.map { |a| a.format }
Mail::AddressContainer.new(self, list)
end

# Returns the display name of all the addresses in the address list
def display_names
list = tree.addresses.map { |a| a.display_name }
Mail::AddressContainer.new(self, list)
end

# Returns the actual address objects in the address list
def addrs
list = tree.addresses
Mail::AddressContainer.new(self, list)
end

# Returns a hash of group name => address strings for the address list
def groups
@groups = Hash.new
Expand All @@ -59,7 +81,7 @@ def groups
end
@groups
end

# Returns the addresses that are part of groups
def group_addresses
decoded_group_addresses
Expand All @@ -79,7 +101,7 @@ def encoded_group_addresses
def group_names # :nodoc:
tree.group_names
end

def default
addresses
end
Expand All @@ -99,9 +121,9 @@ def value=(val)
super
parse(self.value)
end

private

def do_encode(field_name)
return '' if value.blank?
address_array = tree.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
Expand All @@ -114,6 +136,7 @@ def do_encode(field_name)

def do_decode
return nil if value.blank?
return value if charset.to_s.downcase == 'iso-2022-jp'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this return early?

address_array = tree.addresses.reject { |a| decoded_group_addresses.include?(a.decoded) }.map { |a| a.decoded }
address_text = address_array.join(", ")
group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
Expand All @@ -126,7 +149,7 @@ def do_decode
def tree # :nodoc:
@tree ||= AddressList.new(value)
end

def get_group_addresses(group_list)
if group_list.respond_to?(:addresses)
group_list.addresses.map do |address_tree|
Expand All @@ -136,5 +159,13 @@ def get_group_addresses(group_list)
[]
end
end

def encode_with_iso_2022_jp(string)
if md = string.match(/ <[\x00-\x7f]*>\z/)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be 1 or more matches? + vs *

RubyVer.encode_with_iso_2022_jp(md.pre_match) + md[0]
else
string
end
end
end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/from_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,6 @@ class FromField < StructuredField

FIELD_NAME = 'from'
CAPITALIZED_FIELD = 'From'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/reply_to_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,5 @@ class ReplyToField < StructuredField
FIELD_NAME = 'reply-to'
CAPITALIZED_FIELD = 'Reply-To'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/resent_bcc_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,5 @@ class ResentBccField < StructuredField
FIELD_NAME = 'resent-bcc'
CAPITALIZED_FIELD = 'Resent-Bcc'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/resent_cc_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,5 @@ class ResentCcField < StructuredField
FIELD_NAME = 'resent-cc'
CAPITALIZED_FIELD = 'Resent-Cc'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/resent_from_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,5 @@ class ResentFromField < StructuredField
FIELD_NAME = 'resent-from'
CAPITALIZED_FIELD = 'Resent-From'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
19 changes: 2 additions & 17 deletions lib/mail/fields/resent_sender_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,10 @@ module Mail
class ResentSenderField < StructuredField

include Mail::CommonAddress

FIELD_NAME = 'resent-sender'
CAPITALIZED_FIELD = 'Resent-Sender'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end


def addresses
[address.address]
end
Expand All @@ -50,13 +43,5 @@ def address
tree.addresses.first
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
15 changes: 0 additions & 15 deletions lib/mail/fields/resent_to_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,5 @@ class ResentToField < StructuredField
FIELD_NAME = 'resent-to'
CAPITALIZED_FIELD = 'Resent-To'

def initialize(value = nil, charset = 'utf-8')
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
end

def encoded
do_encode(CAPITALIZED_FIELD)
end

def decoded
do_decode
end

end
end
9 changes: 1 addition & 8 deletions lib/mail/fields/return_path_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,13 @@ class ReturnPathField < StructuredField

def initialize(value = nil, charset = 'utf-8')
value = nil if value == '<>'
self.charset = charset
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
self.parse
self
super(value, charset)
end

def encoded
"#{CAPITALIZED_FIELD}: <#{address}>\r\n"
end

def decoded
do_decode
end

def address
addresses.first
end
Expand Down
Loading