]> git.cworth.org Git - sup/blobdiff - lib/sup/util.rb
fixed off-by-one error in imap.rb and maildir.rb
[sup] / lib / sup / util.rb
index 3ffb92bc39ab04db182873c19268ed7b6a5c19d3..ceaf0b8dabc8a83ea451005e9b27bc109823caf1 100644 (file)
@@ -1,3 +1,4 @@
+require 'thread'
 require 'lockfile'
 require 'mime/types'
 require 'pathname'
@@ -37,16 +38,7 @@ class Pathname
       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
+    s.to_human_size
   end
 
   def human_time
@@ -63,33 +55,35 @@ module RMail
   class EncodingUnsupportedError < StandardError; end
 
   class Message
-    def add_file_attachment fn
+    def self.make_file_attachment fn
       bfn = File.basename fn
-      a = Message.new
       t = MIME::Types.type_for(bfn).first || MIME::Types.type_for("exe").first
+      make_attachment IO.read(fn), t.content_type, t.encoding, bfn.to_s
+    end
+
+    def charset
+      if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/i
+        $1
+      end
+    end
 
-      a.header.add "Content-Disposition", "attachment; filename=#{bfn.to_s.inspect}"
-      a.header.add "Content-Type", "#{t.content_type}; name=#{bfn.to_s.inspect}"
-      a.header.add "Content-Transfer-Encoding", t.encoding
+    def self.make_attachment payload, mime_type, encoding, filename
+      a = Message.new
+      a.header.add "Content-Disposition", "attachment; filename=#{filename.inspect}"
+      a.header.add "Content-Type", "#{mime_type}; name=#{filename.inspect}"
+      a.header.add "Content-Transfer-Encoding", encoding if encoding
       a.body =
-        case t.encoding
+        case encoding
         when "base64"
-          [IO.read(fn)].pack "m"
+          [payload].pack "m"
         when "quoted-printable"
-          [IO.read(fn)].pack "M"
-        when "7bit", "8bit"
-          IO.read(fn)
+          [payload].pack "M"
+        when "7bit", "8bit", nil
+          payload
         else
-          raise EncodingUnsupportedError, t.encoding
+          raise EncodingUnsupportedError, encoding.inspect
         end
-
-      add_part a
-    end
-
-    def charset
-      if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/
-        $1
-      end
+      a
     end
   end
 end
@@ -294,14 +288,21 @@ class Numeric
   end
 
   def in? range; range.member? self; end
+
+  def to_human_size
+    if self < 1024
+      to_s + "b"
+    elsif self < (1024 * 1024)
+      (self / 1024).to_s + "k"
+    elsif self < (1024 * 1024 * 1024)
+      (self / 1024 / 1024).to_s + "m"
+    else
+      (self / 1024 / 1024 / 1024).to_s + "g"
+    end
+  end
 end
 
 class Fixnum
-  def num_digits base=10
-    return 1 if self == 0
-    1 + (Math.log(self) / Math.log(10)).floor
-  end
-  
   def to_character
     if self < 128 && self >= 0
       chr
@@ -573,3 +574,42 @@ class SavingHash
 
   defer_all_other_method_calls_to :hash
 end
+
+class OrderedHash < Hash
+  alias_method :store, :[]=
+  alias_method :each_pair, :each
+  attr_reader :keys
+
+  def initialize *a
+    @keys = []
+    a.each { |k, v| self[k] = v }
+  end
+
+  def []= key, val
+    @keys << key unless member?(key)
+    super
+  end
+
+  def values; keys.map { |k| self[k] } end
+  def index key; @keys.index key end
+
+  def delete key
+    @keys.delete key
+    super
+  end
+
+  def each; @keys.each { |k| yield k, self[k] } end
+end
+
+## easy thread-safe class for determining who's the "winner" in a race (i.e.
+## first person to hit the finish line
+class FinishLine
+  def initialize
+    @m = Mutex.new
+    @over = false
+  end
+
+  def winner?
+    @m.synchronize { !@over && @over = true }
+  end
+end