Class: Mail::Ruby19

Inherits:
Object
  • Object
show all
Defined in:
lib/mail/version_specific/ruby_1_9.rb

Defined Under Namespace

Classes: BestEffortCharsetEncoder, StrictCharsetEncoder

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.charset_encoderObject

Returns the value of attribute charset_encoder


43
44
45
# File 'lib/mail/version_specific/ruby_1_9.rb', line 43

def charset_encoder
  @charset_encoder
end

Class Method Details

.b_value_decode(str) ⇒ Object


124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/mail/version_specific/ruby_1_9.rb', line 124

def Ruby19.b_value_decode(str)
  match = str.match(/\=\?(.+)?\?[Bb]\?(.*)\?\=/m)
  if match
    charset = match[1]
    str = Ruby19.decode_base64(match[2])
    str = charset_encoder.encode(str, charset)
  end
  transcode_to_scrubbed_utf8(str)
rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
  warn "Encoding conversion failed #{$!}"
  str.dup.force_encoding(Encoding::UTF_8)
end

.b_value_encode(str, encoding = nil) ⇒ Object


119
120
121
122
# File 'lib/mail/version_specific/ruby_1_9.rb', line 119

def Ruby19.b_value_encode(str, encoding = nil)
  encoding = str.encoding.to_s
  [Ruby19.encode_base64(str), encoding]
end

.bracket(str) ⇒ Object


65
66
67
68
69
# File 'lib/mail/version_specific/ruby_1_9.rb', line 65

def Ruby19.bracket( str )
  str = ::Mail::Utilities.unbracket( str )
  str = escape_bracket( str )
  '<' + str + '>'
end

.decode_base64(str) ⇒ Object


71
72
73
74
75
76
# File 'lib/mail/version_specific/ruby_1_9.rb', line 71

def Ruby19.decode_base64(str)
  if !str.end_with?("=") && str.length % 4 != 0
    str = str.ljust((str.length + 3) & ~3, "=")
  end
  str.unpack( 'm' ).first
end

.decode_utf7(utf7) ⇒ Object


109
110
111
112
113
114
115
116
117
# File 'lib/mail/version_specific/ruby_1_9.rb', line 109

def Ruby19.decode_utf7(utf7)
  utf7.gsub(/&([^-]+)?-/n) do
    if $1
      ($1.tr(",", "/") + "===").unpack("m")[0].encode(Encoding::UTF_8, Encoding::UTF_16BE)
    else
      "&"
    end
  end
end

.encode_base64(str) ⇒ Object


78
79
80
# File 'lib/mail/version_specific/ruby_1_9.rb', line 78

def Ruby19.encode_base64(str)
  [str].pack( 'm' )
end

.encode_utf7(string) ⇒ Object

From Ruby stdlib Net::IMAP


98
99
100
101
102
103
104
105
106
107
# File 'lib/mail/version_specific/ruby_1_9.rb', line 98

def Ruby19.encode_utf7(string)
  string.gsub(/(&)|[^\x20-\x7e]+/) do
    if $1
      "&-"
    else
      base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0")
      "&" + base64.delete("=").tr("/", ",") + "-"
    end
  end.force_encoding(Encoding::ASCII_8BIT)
end

.escape_bracket(str) ⇒ Object


60
61
62
63
# File 'lib/mail/version_specific/ruby_1_9.rb', line 60

def Ruby19.escape_bracket( str )
  re = /(?<!\\)([\<\>])/          # Only match unescaped brackets
  str.gsub(re) { |s| '\\' + s }
end

.escape_paren(str) ⇒ Object

Escapes any parenthesis in a string that are unescaped this uses a Ruby 1.9.1 regexp feature of negative look behind


49
50
51
52
# File 'lib/mail/version_specific/ruby_1_9.rb', line 49

def Ruby19.escape_paren( str )
  re = /(?<!\\)([\(\)])/          # Only match unescaped parens
  str.gsub(re) { |s| '\\' + s }
end

.get_constant(klass, string) ⇒ Object


86
87
88
# File 'lib/mail/version_specific/ruby_1_9.rb', line 86

def Ruby19.get_constant(klass, string)
  klass.const_get( string )
end

.has_constant?(klass, string) ⇒ Boolean

Returns:

  • (Boolean)

82
83
84
# File 'lib/mail/version_specific/ruby_1_9.rb', line 82

def Ruby19.has_constant?(klass, string)
  klass.const_defined?( string, false )
end

.param_decode(str, encoding) ⇒ Object


161
162
163
164
165
166
167
168
# File 'lib/mail/version_specific/ruby_1_9.rb', line 161

def Ruby19.param_decode(str, encoding)
  str = uri_parser.unescape(str)
  str = charset_encoder.encode(str, encoding) if encoding
  transcode_to_scrubbed_utf8(str)
rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
  warn "Encoding conversion failed #{$!}"
  str.dup.force_encoding(Encoding::UTF_8)
end

.param_encode(str) ⇒ Object


170
171
172
173
174
# File 'lib/mail/version_specific/ruby_1_9.rb', line 170

def Ruby19.param_encode(str)
  encoding = str.encoding.to_s.downcase
  language = Configuration.instance.param_encode_language
  "#{encoding}'#{language}'#{uri_parser.escape(str)}"
end

.paren(str) ⇒ Object


54
55
56
57
58
# File 'lib/mail/version_specific/ruby_1_9.rb', line 54

def Ruby19.paren( str )
  str = ::Mail::Utilities.unparen( str )
  str = escape_paren( str )
  '(' + str + ')'
end

.pick_encoding(charset) ⇒ Object

Pick a Ruby encoding corresponding to the message charset. Most charsets have a Ruby encoding, but some need manual aliasing here.

TODO: add this as a test somewhere:

Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b}
Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b}

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/mail/version_specific/ruby_1_9.rb', line 186

def Ruby19.pick_encoding(charset)
  charset = charset.to_s
  encoding = case charset.downcase

  # ISO-8859-8-I etc. http://en.wikipedia.org/wiki/ISO-8859-8-I
  when /^iso[-_]?8859-(\d+)(-i)?$/
    "ISO-8859-#{$1}"

  # ISO-8859-15, ISO-2022-JP and alike
  when /^iso[-_]?(\d{4})-?(\w{1,2})$/
    "ISO-#{$1}-#{$2}"

  # "ISO-2022-JP-KDDI"  and alike
  when /^iso[-_]?(\d{4})-?(\w{1,2})-?(\w*)$/
    "ISO-#{$1}-#{$2}-#{$3}"

  # UTF-8, UTF-32BE and alike
  when /^utf[\-_]?(\d{1,2})?(\w{1,2})$/
    "UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE')

  # Windows-1252 and alike
  when /^windows-?(.*)$/
    "Windows-#{$1}"

  when '8bit'
    Encoding::ASCII_8BIT

  # alternatives/misspellings of us-ascii seen in the wild
  when /^iso[-_]?646(-us)?$/, 'us=ascii'
    Encoding::ASCII

  # Microsoft-specific alias for MACROMAN
  when 'macintosh'
    Encoding::MACROMAN

  # Microsoft-specific alias for CP949 (Korean)
  when 'ks_c_5601-1987'
    Encoding::CP949

  # Wrongly written Shift_JIS (Japanese)
  when 'shift-jis'
    Encoding::Shift_JIS

  # GB2312 (Chinese charset) is a subset of GB18030 (its replacement)
  when 'gb2312'
    Encoding::GB18030

  when 'cp-850'
    Encoding::CP850

  when 'latin2'
    Encoding::ISO_8859_2

  else
    charset
  end

  convert_to_encoding(encoding)
end

.q_value_decode(str) ⇒ Object


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/mail/version_specific/ruby_1_9.rb', line 142

def Ruby19.q_value_decode(str)
  match = str.match(/\=\?(.+)?\?[Qq]\?(.*)\?\=/m)
  if match
    charset = match[1]
    string = match[2].gsub(/_/, '=20')
    # Remove trailing = if it exists in a Q encoding
    string = string.sub(/\=$/, '')
    str = Encodings::QuotedPrintable.decode(string)
    str = charset_encoder.encode(str, charset)
    # We assume that binary strings hold utf-8 directly to work around
    # jruby/jruby#829 which subtly changes String#encode semantics.
    str.force_encoding(Encoding::UTF_8) if str.encoding == Encoding::ASCII_8BIT
  end
  transcode_to_scrubbed_utf8(str)
rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
  warn "Encoding conversion failed #{$!}"
  str.dup.force_encoding(Encoding::UTF_8)
end

.q_value_encode(str, encoding = nil) ⇒ Object


137
138
139
140
# File 'lib/mail/version_specific/ruby_1_9.rb', line 137

def Ruby19.q_value_encode(str, encoding = nil)
  encoding = str.encoding.to_s
  [Encodings::QuotedPrintable.encode(str), encoding]
end

.string_byteslice(str, *args) ⇒ Object


247
248
249
# File 'lib/mail/version_specific/ruby_1_9.rb', line 247

def Ruby19.string_byteslice(str, *args)
  str.byteslice(*args)
end

.transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8) ⇒ Object


90
91
92
93
94
95
# File 'lib/mail/version_specific/ruby_1_9.rb', line 90

def Ruby19.transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8)
  to_encoding = to_encoding.to_s if RUBY_VERSION < '1.9.3'
  to_encoding = Encoding.find(to_encoding)
  replacement_char = to_encoding == Encoding::UTF_8 ? '' : '?'
  charset_encoder.encode(str.dup, from_encoding).encode(to_encoding, :undef => :replace, :invalid => :replace, :replace => replacement_char)
end

.uri_parserObject


176
177
178
# File 'lib/mail/version_specific/ruby_1_9.rb', line 176

def Ruby19.uri_parser
  URI::DEFAULT_PARSER
end