+require 'lockfile'
+require 'mime/types'
+require 'pathname'
+
+## time for some monkeypatching!
+class Lockfile
+ def gen_lock_id
+ Hash[
+ 'host' => "#{ Socket.gethostname }",
+ 'pid' => "#{ Process.pid }",
+ 'ppid' => "#{ Process.ppid }",
+ 'time' => timestamp,
+ 'pname' => $0,
+ 'user' => ENV["USER"]
+ ]
+ end
+
+ 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
+
+ def lockinfo_on_disk
+ h = load_lock_id IO.read(path)
+ h['mtime'] = File.mtime path
+ h
+ end
+
+ def touch_yourself; touch path end
+end
+
+class Pathname
+ def human_size
+ s =
+ begin
+ size
+ rescue SystemCallError
+ return "?"
+ end
+
+ if s < 1024
+ s.to_s + "b"
+ elsif s < (1024 * 1024)
+ (s / 1024).to_s + "k"
+ elsif s < (1024 * 1024 * 1024)
+ (s / 1024 / 1024).to_s + "m"
+ else
+ (s / 1024 / 1024 / 1024).to_s + "g"
+ end
+ end
+
+ def human_time
+ begin
+ ctime.strftime("%Y-%m-%d %H:%M")
+ rescue SystemCallError
+ "?"
+ end
+ end
+end
+
+## more monkeypatching!
+module RMail
+ class EncodingUnsupportedError < StandardError; end
+
+ class Message
+ def add_file_attachment fn
+ bfn = File.basename fn
+ a = Message.new
+ t = MIME::Types.type_for(bfn).first || MIME::Types.type_for("exe").first
+
+ a.header.add "Content-Disposition", "attachment; filename=#{bfn}"
+ a.header.add "Content-Type", "#{t.content_type}; name=#{bfn}"
+ a.header.add "Content-Transfer-Encoding", t.encoding
+ a.body =
+ case t.encoding
+ when "base64"
+ [IO.read(fn)].pack "m"
+ when "quoted-printable"
+ [IO.read(fn)].pack "M"
+ when "7bit", "8bit"
+ IO.read(fn)
+ else
+ raise EncodingUnsupportedError, t.encoding
+ end
+
+ add_part a
+ end
+
+ def charset
+ if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/
+ $1
+ end
+ end
+ end
+end
+
+class Range
+ ## only valid for integer ranges (unless I guess it's exclusive)
+ def size
+ last - first + (exclude_end? ? 0 : 1)
+ end
+end
+