]> git.cworth.org Git - sup/commitdiff
imap error handling refactorization
authorwmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Mon, 8 Jan 2007 19:03:15 +0000 (19:03 +0000)
committerwmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Mon, 8 Jan 2007 19:03:15 +0000 (19:03 +0000)
git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@228 5c8cc53c-5e98-4d25-b20a-d8db53a31250

bin/sup
lib/sup/imap.rb

diff --git a/bin/sup b/bin/sup
index 3b4a34cc89faac3eea36d1d2e607f7337b121fc5..8c785e477584ad1f62202d7dfdb7c8e09e0f7559 100644 (file)
--- a/bin/sup
+++ b/bin/sup
@@ -187,6 +187,12 @@ rescue Exception => e
 ensure
   Redwood::finish
   stop_cursing
+  
+  # don't ask me why, but sometimes it's necessary to print something
+  # to stderr at this point or the exception doesn't get printed.
+  # doesn't get printed. WHY?
+
+  $stderr.puts " " 
 end
 
 Index.save unless $exception # TODO: think about this
index 4108a6a9510833d058b56c5cd032f4f514637b89..4be96fc342c64409206e8f0ef3e31ba3c87a8859 100644 (file)
@@ -88,23 +88,15 @@ class IMAP < Source
   end
 
   def connect
-    return false if broken?
-    return true if @imap
+    return if broken? || @imap
 
     say "Connecting to IMAP server #{host}:#{port}..."
 
-    ## ok, this is FUCKING ANNOYING.
-    ##
-    ## what imap.rb likes to do is, if an exception occurs, catch it
-    ## and re-raise it on the calling thread. seems reasonable. but
-    ## what that REALLY means is that the only way to reasonably
-    ## initialize imap is in its own thread, because otherwise, you
-    ## will never be able to catch the exception it raises on the
-    ## calling thread, and the backtrace will not make any sense at
-    ## all, and you will waste HOURS of your life on this fucking
-    ## problem.
-    ##
-    ## FUCK!!!!!!!!!
+    ## apparently imap.rb does a lot of threaded stuff internally and
+    ## if an exception occurs, it will catch it and re-raise it on the
+    ## calling thread. but i can't seem to catch that exception, so
+    ## i've resorted to initializing it in its own thread. surely
+    ## there's a better way.
 
     exception = nil
     Redwood::reporting_thread do
@@ -115,7 +107,7 @@ class IMAP < Source
 
         ## although RFC1730 claims that "If an AUTHENTICATE command
         ## fails with a NO response, the client may try another", in
-        ## practice it seems like they will also send BAD responses.
+        ## practice it seems like they can also send a BAD response.
         begin
           @imap.authenticate 'CRAM-MD5', @username, @password
         rescue Net::IMAP::BadResponseError, Net::IMAP::NoResponseError => e
@@ -128,7 +120,7 @@ class IMAP < Source
           end
         end
         scan_mailbox
-        say "Successfully connected to #{@parsed_uri}."
+        say "Successfully connected to #{@parsed_uri}." unless broken?
       rescue SocketError, Net::IMAP::Error, SourceError => e
         exception = e
       ensure
@@ -140,7 +132,7 @@ class IMAP < Source
   end
 
   def each
-    @mutex.synchronize { connect or raise SourceError, broken_msg }
+    @mutex.synchronize { connect }
 
     start = @ids.index(cur_offset || start_offset) or die_from "Unknown message id #{cur_offset || start_offset}.", :suggest_rebuild => true # couldn't find the most recent email
 
@@ -158,12 +150,8 @@ class IMAP < Source
 
   def end_offset
     @mutex.synchronize do
-      begin
-        connect
-        scan_mailbox
-      rescue SocketError, Net::IMAP::Error => e
-        die_from e, :while => "scanning mailbox"
-      end
+      connect
+      scan_mailbox
     end
     @ids.last
   end
@@ -185,12 +173,15 @@ private
   def scan_mailbox
     return if @last_scan && (Time.now - @last_scan) < SCAN_INTERVAL
 
-    @imap.examine mailbox
-    last_id = @imap.responses["EXISTS"].last
+    last_id = safely do
+      @imap.examine mailbox
+      @imap.responses["EXISTS"].last
+    end
+
     @last_scan = Time.now
     return if last_id == @ids.length
     Redwood::log "fetching IMAP headers #{(@ids.length + 1) .. last_id}"
-    values = @imap.fetch((@ids.length + 1) .. last_id, ['RFC822.SIZE', 'INTERNALDATE'])
+    values = safely { @imap.fetch((@ids.length + 1) .. last_id, ['RFC822.SIZE', 'INTERNALDATE']) }
     values.each do |v|
       id = make_id v
       @ids << id
@@ -225,26 +216,34 @@ private
   end
 
   def get_imap_fields id, *fields
-    retries = 0
-    f = nil
+    raise SourceError, broken_msg if broken?
     imap_id = @imap_ids[id] or die_from "Unknown message id #{id}.", :suggest_rebuild => true
+
+    retried = false
+    results = safely { @imap.fetch imap_id, (fields + ['RFC822.SIZE', 'INTERNALDATE']).uniq }.first
+    got_id = make_id results
+    die_from "IMAP message mismatch: requested #{id}, got #{got_id}.", :suggest_rebuild => true unless got_id == id
+
+    fields.map { |f| results.attr[f] }
+  end
+
+  def safely
     begin
-      f = @imap.fetch imap_id, (fields + ['RFC822.SIZE', 'INTERNALDATE']).uniq
-      got_id = make_id f[0]
-      die_from "IMAP message mismatch: requested #{id}, got #{got_id}.", :suggest_rebuild => true unless id == got_id
-    rescue SocketError, Net::IMAP::Error => e
+      yield
+    rescue Net, SocketError, Net::IMAP::Error => e
       die_from e, :while => "communicating with IMAP server"
     rescue Errno::EPIPE
-      if (retries += 1) <= 3
+      unless retried
+        retried = true
         @imap = nil
         connect
         retry
+      else
+        die_from e, :while => "communicating with IMAP server"
       end
     end
-    die_from "Null IMAP field '#{field}' for message with id #{id} imap id #{imap_id}." if f.nil?
-
-    fields.map { |field| f[0].attr[field] }
   end
+
 end
 
 Redwood::register_yaml(IMAP, %w(uri username password cur_offset usual archived id))