Linux で mhtml(.mht ファイル) を見たくて検索したけど適当な方法がなかった。mhtml の仕様を調べたら、基本的にメールのフォーマットなんで、ruby で何とかできるだろうという事でスクリプトを書いてみた。
~/.rmhtml/ ディレクトリを作ってそこに適当にファイルを展開して、firefox を呼び出すというスクリプト。これを .mht ファイルと関連付ければ、mhtml ファイルを firefox から閲覧することが出来る。要 TMail と htree。
#!/usr/local/bin/ruby-1.8
require 'pp'
require 'kconv'
require 'digest/md5'
require 'tmail'
require 'htree'
require "optparse"
Rmhtml_dir = File.join ENV['HOME'], '.rmhtml'
if File.exist?(Rmhtml_dir)
unless File.directory?(Rmhtml_dir)
raise RmhtmlError, "#{Rmhtml_dir} exists and is not a directory."
end
else
Dir.mkdir Rmhtml_dir
end
class RmhtmlError < StandardError
end
class Rmhtml
Config = {}
def initialize(filename)
@mail = TMail::Mail.load(filename)
if /text\/html/ =~ @mail.parts[0].content_type
@main_part = @mail.parts[0]
else
each_part(@mail){|e|
if /text\/html/ =~ e.content_type
@main_part = e
break
end
}
raise RmhtmlError, 'main html part does not exist.' unless @main_part
end
@mail.parts.delete(@main_part)
end
def each_part(mail, &b)
mail.parts.each{|e|
unless /multipart\/alternative/i =~ e.content_type
yield e
else
each_part(e, &b)
end
}
end
def get_objects
@main_html = decode(@main_part)
ret = []
@obj_locs = {}
each_part(@mail){|e|
filename = filename(e)
obj = decode(e)
@obj_locs[location(e)] = true
ret << [filename, obj]
}
return ret
end
def location(mail)
mail['Content-Location'].to_s.toeuc
end
def filename(mail)
case mail
when String
Digest::MD5.hexdigest(mail.toeuc)
else
Digest::MD5.hexdigest(location(mail))
end
end
def md5(s)
Digest::MD5.hexdigest(s.toeuc)
end
def dir_name
File.join(Rmhtml_dir, filename(@main_part) )
end
def mkdir
if File.exist? dir_name
return :exist
else
Dir.mkdir dir_name
end
end
def decode(mail)
case mail.transfer_encoding
when /quoted-printable/i
mail.body.unpack('M')[0]
when /Base64/i
mail.body.unpack('m')[0]
end
end
def do_store
d = mkdir()
if d != :exist or Config[:f]
Dir.chdir(dir_name)
objs = get_objects()
objs.each{|filename, obj|
File.open(filename, 'w').write(obj)
}
html = change_src_in_main_html()
File.open(filename(@main_part), 'w').write(html)
end
return File.join(dir_name, filename(@main_part))
end
def change_src_in_main_html
htr = HTree(@main_html).root
objs = {}
htr = change_src(htr)
ret = ''
htr.display_xml(ret)
return ret
end
def is_stylesheet_link_tag?(e)
/link/i =~ e.element_name.to_s and
/stylesheet/i =~ e.get_attr('rel').to_s and
/text\/css/i =~ e.get_attr('type').to_s
end
def change_src(elms)
objs = {}
elms.each_child_with_index{|e, ind|
next unless e.is_a? HTree::Elem
if src = e.get_attr('src') and @obj_locs[src.to_s.toeuc]
e = e.subst_subnode( {'src' => filename(src.to_s) } )
elsif is_stylesheet_link_tag?(e) and href = e.get_attr('href') and @obj_locs[href.to_s.toeuc]
e = e.subst_subnode( {'href' => filename(href.to_s) } )
end
e2 = change_src(e)
objs[ind] = e2
}
elms.subst_subnode(objs)
end
end
opts = OptionParser.new
opts.on("-f"){|v| Rmhtml::Config[:f] = true }
opts.parse!(ARGV)
rmhtml = Rmhtml.new(ARGV[0])
html = rmhtml.do_store()
system "firefox #{html.dump}"
ちょっと改良。 既存の html ファイルの特定の条件に合う要素だけ入替えるというのは、htree ではやりにくい。他に何かやり方があるのだろうか。
最近のコメント