module Mail::Encodings - mail-2.5.4 Documentation

# module Mail::Encodings

### Public Class Methods

address_encode(address, charset = 'utf-8') click to toggle source

    # File lib/mail/encodings.rb, line 174
    def Encodings.address_encode(address, charset = 'utf-8')
      if address.is_a?(Array)
        # loop back through for each element
        address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
      else
        # find any word boundary that is not ascii and encode it
        encode_non_usascii(address, charset) if address
      end
    end

b_value_encode(encoded_str, encoding = nil) click to toggle source

Encode a string with Base64 Encoding and returns it ready to be inserted as a value for a field, that is, in the =?<charset>?B?<string>?= format

Example:

    Encodings.b_value_encode('This is あ string', 'UTF-8')
    #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="

    # File lib/mail/encodings.rb, line 211
    def Encodings.b_value_encode(encoded_str, encoding = nil)
      return encoded_str if encoded_str.to_s.ascii_only?
      string, encoding = RubyVer.b_value_encode(encoded_str, encoding)
      map_lines(string) do |str|
        "=?#{encoding}?B?#{str.chomp}?="
      end.join(" ")
    end

decode_encode(str, output_type) click to toggle source

Decodes or encodes a string as needed for either Base64 or QP encoding types in the =?<encoding>??<string>?=“ format.

The output type needs to be :decode to decode the input string or :encode to encode the input string. The character set used for encoding will either be the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in.

On encoding, will only send out Base64 encoded strings.

    # File lib/mail/encodings.rb, line 97
    def Encodings.decode_encode(str, output_type)
      case
      when output_type == :decode
        Encodings.value_decode(str)
      else
        if str.ascii_only?
          str
        else
          Encodings.b_value_encode(str, find_encoding(str))
        end
      end
    end

defined?( str ) click to toggle source

Is the encoding we want defined?

Example:

    Encodings.defined?(:base64) #=> true

    # File lib/mail/encodings.rb, line 28
    def Encodings.defined?( str )
      @transfer_encodings.include? get_name(str)
    end

encode_non_usascii(address, charset) click to toggle source

    # File lib/mail/encodings.rb, line 184
    def Encodings.encode_non_usascii(address, charset)
      return address if address.ascii_only? or charset.nil?
      us_ascii = %Q{\x00-\x7f}
      # Encode any non usascii strings embedded inside of quotes
      address = address.gsub(/(".*?[^#{us_ascii}].*?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
      # Then loop through all remaining items and encode as needed
      tokens = address.split(/\s/)
      map_with_index(tokens) do |word, i|
        if word.ascii_only?
          word
        else
          previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
          if previous_non_ascii #why are we adding an extra space here?
            word = " #{word}"
          end
          Encodings.b_value_encode(word, charset)
        end
      end.join(' ')
    end

get_all() click to toggle source

    # File lib/mail/encodings.rb, line 44
    def Encodings.get_all
      @transfer_encodings.values
    end

get_encoding( str ) click to toggle source

Gets a defined encoding type, QuotedPrintable or Base64 for now.

Each encoding needs to be defined as a Mail::Encodings::ClassName for this to work, allows us to add other encodings in the future.

Example:

    Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64

    # File lib/mail/encodings.rb, line 40
    def Encodings.get_encoding( str )
      @transfer_encodings[get_name(str)]
    end

get_name(enc) click to toggle source

    # File lib/mail/encodings.rb, line 48
    def Encodings.get_name(enc)
      enc = enc.to_s.gsub("-", "_").downcase
    end

param_decode(str, encoding) click to toggle source

Decodes a parameter value using URI Escaping.

Example:

    Mail::Encodings.param_decode("This%20is%20fun", 'us-ascii') #=> "This is fun"

    str = Mail::Encodings.param_decode("This%20is%20fun", 'iso-8559-1')
    str.encoding #=> 'ISO-8859-1'      ## Only on Ruby 1.9
    str #=> "This is fun"

    # File lib/mail/encodings.rb, line 85
    def Encodings.param_decode(str, encoding)
      RubyVer.param_decode(str, encoding)
    end

param_encode(str) click to toggle source

Encodes a parameter value using URI Escaping, note the language field 'en' can be set using Mail::Configuration, like so:

    Mail.defaults do
      param_encode_language 'jp'
    end

The character set used for encoding will either be the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in.

Example:

    Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun"

    # File lib/mail/encodings.rb, line 65
    def Encodings.param_encode(str)
      case
      when str.ascii_only? && str =~ TOKEN_UNSAFE
        %Q{"#{str}"}
      when str.ascii_only?
        str
      else
        RubyVer.param_encode(str)
      end
    end

q_value_encode(encoded_str, encoding = nil) click to toggle source

Encode a string with Quoted-Printable Encoding and returns it ready to be inserted as a value for a field, that is, in the =?<charset>?Q?<string>?= format

Example:

    Encodings.q_value_encode('This is あ string', 'UTF-8')
    #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="

    # File lib/mail/encodings.rb, line 226
    def Encodings.q_value_encode(encoded_str, encoding = nil)
      return encoded_str if encoded_str.to_s.ascii_only?
      string, encoding = RubyVer.q_value_encode(encoded_str, encoding)
      string.gsub!("=\r\n", '') # We already have limited the string to the length we want
      map_lines(string) do |str|
        "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
      end.join(" ")
    end

register(name, cls) click to toggle source

Register transfer encoding

Example

::register “base64”, Mail::Encodings::Base64

    # File lib/mail/encodings.rb, line 19
    def Encodings.register(name, cls)
        @transfer_encodings[get_name(name)] = cls
    end

unquote_and_convert_to(str, to_encoding) click to toggle source

Takes an encoded string of the format =?<encoding>??<string>?=

    # File lib/mail/encodings.rb, line 147
    def Encodings.unquote_and_convert_to(str, to_encoding)
      output = value_decode( str ).to_s # output is already converted to UTF-8

      if 'utf8' == to_encoding.to_s.downcase.gsub("-", "")
        output
      elsif to_encoding
        begin
          if RUBY_VERSION >= '1.9'
            output.encode(to_encoding)
          else
            require 'iconv'
            Iconv.iconv(to_encoding, 'UTF-8', output).first
          end
        rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
          # the 'from' parameter specifies a charset other than what the text
          # actually is...not much we can do in this case but just return the
          # unconverted text.
          #
          # Ditto if either parameter represents an unknown charset, like
          # X-UNKNOWN.
          output
        end
      else
        output
      end
    end

value_decode(str) click to toggle source

Decodes a given string as Base64 or Quoted Printable, depending on what type it is.

String has to be of the format =?<encoding>??<string>?=

    # File lib/mail/encodings.rb, line 114
    def Encodings.value_decode(str)
      # Optimization: If there's no encoded-words in the string, just return it
      return str unless str =~ /\=\?[^?]+\?[QB]\?[^?]+?\?\=/xmi

      lines = collapse_adjacent_encodings(str)

      # Split on white-space boundaries with capture, so we capture the white-space as well
      lines.map do |line|
        line.split(/([ \t])/).map do |text|
          if text.index('=?').nil?
            text
          else
            # Search for occurences of quoted strings or plain strings
            text.scan(/(                                 # Group around entire regex to include it in matches
                        \=\?[^?]+\?([QB])\?[^?]+?\?\=    # Quoted String with subgroup for encoding method
                        |                                # or
                        .+?(?=\=\?|$)                    # Plain String
                      )/xmi).map do |matches|
              string, method = *matches
              if    method == 'b' || method == 'B'
                b_value_decode(string)
              elsif method == 'q' || method == 'Q'
                q_value_decode(string)
              else
                string
              end
            end
          end
        end
      end.flatten.join("")
    end

### Private Class Methods

b_value_decode(str) click to toggle source

Decodes a Base64 string from the “=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=” format

Example:

    Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
    #=> 'This is あ string'

    # File lib/mail/encodings.rb, line 243
    def Encodings.b_value_decode(str)
      RubyVer.b_value_decode(str)
    end

collapse_adjacent_encodings(str) click to toggle source

When the encoded string consists of multiple lines, lines with the same encoding (Q or B) can be joined together.

String has to be of the format =?<encoding>??<string>?=

    # File lib/mail/encodings.rb, line 284
    def Encodings.collapse_adjacent_encodings(str)
      lines = str.split(/(\?=)\s*(=\?)/).each_slice(2).map(&:join)
      results = []
      previous_encoding = nil

      lines.each do |line|
        encoding = split_value_encoding_from_string(line)

        if encoding == previous_encoding
          line = results.pop + line
          line.gsub!(/\?\=\=\?.+?\?[QqBb]\?/m, '')
        end

        previous_encoding = encoding
        results << line
      end

      results
    end

find_encoding(str) click to toggle source

    # File lib/mail/encodings.rb, line 266
    def Encodings.find_encoding(str)
      RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
    end

q_value_decode(str) click to toggle source

Decodes a Quoted-Printable string from the “=?UTF-8?Q?This_is_=E3=81=82_string?=” format

Example:

    Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
    #=> 'This is あ string'

    # File lib/mail/encodings.rb, line 253
    def Encodings.q_value_decode(str)
      RubyVer.q_value_decode(str)
    end

split_encoding_from_string( str ) click to toggle source

    # File lib/mail/encodings.rb, line 257
    def Encodings.split_encoding_from_string( str )
      match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi)
      if match
        match[1]
      else
        nil
      end
    end

split_value_encoding_from_string(str) click to toggle source

Gets the encoding type (Q or B) from the string.

    # File lib/mail/encodings.rb, line 271
    def Encodings.split_value_encoding_from_string(str)
      match = str.match(/\=\?[^?]+?\?([QB])\?(.+)?\?\=/mi)
      if match
        match[1]
      else
        nil
      end
    end