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 ではやりにくい。他に何かやり方があるのだろうか。
最近のコメント