commit c54156ce142289514bd45c3776cd2ce8ef4a8a00
parent 2ad87067a6190ab0c8626c1f6532cc0c003bbe15
Author: Gaute Hope <eg@gaute.vetsj.com>
Date: Sun, 26 May 2013 13:22:25 +0200
Replace Iconv with built-ins for Ruby >=1.9
Diffstat:
5 files changed, 67 insertions(+), 44 deletions(-)
diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb
@@ -74,7 +74,7 @@ EOS
end
unless @gpgme_present
- @not_working_reason = ['gpgme gem not present',
+ @not_working_reason = ['gpgme gem not present',
'Install the gpgme gem in order to use signed and encrypted emails']
return
end
@@ -85,7 +85,7 @@ EOS
else
# check if the gpg-options hook uses the passphrase_callback
# if it doesn't then check if gpg agent is present
- gpg_opts = HookManager.run("gpg-options",
+ gpg_opts = HookManager.run("gpg-options",
{:operation => "sign", :options => {}}) || {}
if gpg_opts[:passphrase_callback].nil?
if ENV['GPG_AGENT_INFO'].nil?
@@ -116,7 +116,7 @@ EOS
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
gpg_opts.merge!(gen_sign_user_opts(from))
- gpg_opts = HookManager.run("gpg-options",
+ gpg_opts = HookManager.run("gpg-options",
{:operation => "sign", :options => gpg_opts}) || gpg_opts
begin
@@ -125,7 +125,7 @@ EOS
raise Error, gpgme_exc_msg(exc.message)
end
- # if the key (or gpg-agent) is not available GPGME does not complain
+ # if the key (or gpg-agent) is not available GPGME does not complain
# but just returns a zero length string. Let's catch that
if sig.length == 0
raise Error, gpgme_exc_msg("GPG failed to generate signature: check that gpg-agent is running and your key is available.")
@@ -145,7 +145,7 @@ EOS
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
if sign
- gpg_opts.merge!(gen_sign_user_opts(from))
+ gpg_opts.merge!(gen_sign_user_opts(from))
gpg_opts.merge!({:sign => true})
end
gpg_opts = HookManager.run("gpg-options",
@@ -158,7 +158,7 @@ EOS
raise Error, gpgme_exc_msg(exc.message)
end
- # if the key (or gpg-agent) is not available GPGME does not complain
+ # if the key (or gpg-agent) is not available GPGME does not complain
# but just returns a zero length string. Let's catch that
if cipher.length == 0
raise Error, gpgme_exc_msg("GPG failed to generate cipher text: check that gpg-agent is running and your key is available.")
@@ -290,7 +290,7 @@ EOS
# Look for Charset, they are put before the base64 crypted part
charsets = payload.body.split("\n").grep(/^Charset:/)
if !charsets.empty? and charsets[0] =~ /^Charset: (.+)$/
- output = Iconv.easy_decode($encoding, $1, output)
+ output.transcode($encoding, $1)
end
msg.body = output
else
@@ -362,7 +362,7 @@ private
else
first_sig = "Unknown error or empty signature"
end
- rescue EOFError
+ rescue EOFError
from_key = nil
first_sig = "No public key available for #{signature.fingerprint}"
end
diff --git a/lib/sup/message.rb b/lib/sup/message.rb
@@ -69,7 +69,9 @@ class Message
return unless v
return v unless v.is_a? String
return unless v.size < MAX_HEADER_VALUE_SIZE # avoid regex blowup on spam
- Rfc2047.decode_to $encoding, Iconv.easy_decode($encoding, 'ASCII', v)
+ d = v.dup
+ d = d.transcode($encoding, 'ASCII')
+ Rfc2047.decode_to $encoding, d
end
def parse_header encoded_header
@@ -524,7 +526,7 @@ private
## if there's no charset, use the current encoding as the charset.
## this ensures that the body is normalized to avoid non-displayable
## characters
- body = Iconv.easy_decode($encoding, m.charset || $encoding, m.decode)
+ body = m.decode.transcode($encoding, m.charset)
else
body = ""
end
@@ -546,7 +548,7 @@ private
msg = RMail::Message.new
msg.body = gpg.join("\n")
- body = Iconv.easy_decode(encoding_to, encoding_from, body)
+ body = body.transcode(encoding_to, encoding_from)
lines = body.split("\n")
sig = lines.between(GPG_SIGNED_START, GPG_SIG_START)
startidx = lines.index(GPG_SIGNED_START)
diff --git a/lib/sup/message_chunks.rb b/lib/sup/message_chunks.rb
@@ -124,7 +124,7 @@ EOS
@lines = nil
if text
- text = text.transcode(encoded_content.charset || $encoding)
+ text = text.transcode(encoded_content.charset || $encoding, text.encoding)
@lines = text.gsub("\r\n", "\n").gsub(/\t/, " ").gsub(/\r/, "").split("\n")
@quotable = true
end
diff --git a/lib/sup/rfc2047.rb b/lib/sup/rfc2047.rb
@@ -52,7 +52,7 @@ module Rfc2047
# WORD.
end
- Iconv.easy_decode(target, charset, text)
+ text.transcode(target, charset)
end
end
end
diff --git a/lib/sup/util.rb b/lib/sup/util.rb
@@ -5,7 +5,6 @@ require 'pathname'
require 'set'
require 'enumerator'
require 'benchmark'
-require 'iconv'
## time for some monkeypatching!
class Symbol
@@ -31,7 +30,7 @@ class Lockfile
def dump_lock_id lock_id = @lock_id
"host: %s\npid: %s\nppid: %s\ntime: %s\nuser: %s\npname: %s\n" %
lock_id.values_at('host','pid','ppid','time','user', 'pname')
- end
+ end
def lockinfo_on_disk
h = load_lock_id IO.read(path)
@@ -341,7 +340,57 @@ class String
ret << s
end
+ # Fix the damn string! make sure it is valid utf-8, then convert to
+ # user encoding.
+ #
+ # Not Ruby 1.8 compatible
+ def fix_encoding
+ if encoding == $encoding and valid_encoding?
+ self
+ end
+
+ encode!('UTF-8', :invalid => :replace, :undef => :replace)
+
+ unless valid_encoding?
+ encode!('UTF-16', 'UTF-8', :invalid => :replace, :undef => :replace)
+ encode!('UTF-8', 'UTF-16', :invalid => :replace, :undef => :replace)
+ end
+
+ fail "Could not create valid UTF-8 string out of: '#{self.to_s}'." unless valid_encoding?
+
+ # now convert to $encoding
+ if $encoding != 'UTF-8'
+ encode!($encoding, :invalid => :replace, :undef => :replace)
+ end
+
+ fail "Could not create valid #{$encoding.inspect?} string out of: '#{self.to_s}'." unless valid_encoding?
+
+ self
+ end
+
+ # transcode the string if original encoding is know
+ # fix if broken.
+ #
+ # Not Ruby 1.8 compatible
+ def transcode to_encoding, from_encoding
+ encode!(to_encoding, from_encoding, :invalid => :replace, :undef => :replace)
+
+ unless valid_encoding?
+ encode!('UTF-16', 'UTF-8', :invalid => :replace, :undef => :replace)
+ encode!('UTF-8', 'UTF-16', :invalid => :replace, :undef => :replace)
+ end
+
+ if to_encoding != 'UTF-8'
+ encode!(to_encoding, :invalid => :replace, :undef => :replace)
+ end
+
+ fail "Could not create valid #{to_encoding.inspect?} string out of: '#{self.to_s}'." unless valid_encoding?
+
+ self
+ end
+
def normalize_whitespace
+ fix_encoding
gsub(/\t/, " ").gsub(/\r/, "")
end
@@ -383,14 +432,10 @@ class String
out << b.chr
end
end
- out.force_encoding Encoding::UTF_8 if out.respond_to? :force_encoding
+ out.fix_encoding
out
end
- def transcode src_encoding=$encoding
- Iconv.easy_decode $encoding, src_encoding, self
- end
-
unless method_defined? :ascii_only?
def ascii_only?
size.times { |i| return false if self[i] & 128 != 0 }
@@ -659,27 +704,3 @@ class FinishLine
end
end
-class Iconv
- def self.easy_decode target, orig_charset, text
- if text.respond_to? :force_encoding
- text = text.dup
- text.force_encoding Encoding::BINARY
- end
- charset = case orig_charset
- when /UTF[-_ ]?8/i then "utf-8"
- when /(iso[-_ ])?latin[-_ ]?1$/i then "ISO-8859-1"
- when /iso[-_ ]?8859[-_ ]?15/i then 'ISO-8859-15'
- when /unicode[-_ ]1[-_ ]1[-_ ]utf[-_]7/i then "utf-7"
- when /^euc$/i then 'EUC-JP' # XXX try them all?
- when /^(x-unknown|unknown[-_ ]?8bit|ascii[-_ ]?7[-_ ]?bit)$/i then 'ASCII'
- else orig_charset
- end
-
- begin
- returning(Iconv.iconv(target + "//IGNORE", charset, text + " ").join[0 .. -2]) { |str| str.check }
- rescue Errno::EINVAL, Iconv::InvalidEncoding, Iconv::InvalidCharacter, Iconv::IllegalSequence, String::CheckError
- debug "couldn't transcode text from #{orig_charset} (#{charset}) to #{target} (#{text[0 ... 20].inspect}...): got #{$!.class} (#{$!.message})"
- text.ascii
- end
- end
-end