commit 7dce67e920dbb65ac880a9346cc2d00a1b49db1a
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Sat Jun 19 14:42:39 2010 +0200

    [evol] IMAP IDLE support finished (closes #100)

diff --git a/lib/cyborghood/imap.rb b/lib/cyborghood/imap.rb
index 31b32f1..a118b87 100644
--- a/lib/cyborghood/imap.rb
+++ b/lib/cyborghood/imap.rb
@@ -17,6 +17,7 @@
 #++
 
 require 'net/imap'
+require 'thread'
 
 # IMAP IDLE support
 class Net::IMAP
@@ -27,7 +28,7 @@ class Net::IMAP
 
     synchronize do
       @idle_tag = generate_tag
-      add_response_handler @idle_response_handler
+      add_response_handler @idle_response_handler if @idle_response_handler
       put_string "#{@idle_tag} IDLE#{CRLF}"
     end
 
@@ -38,7 +39,7 @@ class Net::IMAP
     return unless @idle_mode
 
     synchronize do
-      remove_response_handler @idle_response_handler
+      remove_response_handler @idle_response_handler if @idle_response_handler
       put_string "DONE#{CRLF}"
     end
 
@@ -64,6 +65,8 @@ module CyborgHood
       @config = Config.instance
       @imap = nil
       @is_loggued = false
+      @available_mails = 0
+      @available_mails_mutex = Mutex.new
 
       if not (@config.debug.nil? or @config.debug.flags.nil?) and @config.debug.flags.include?(:debug_imapverbose)
         Net::IMAP.debug = true
@@ -88,9 +91,9 @@ module CyborgHood
       end
 
       def delete
-	if @config.debug.nil? or @config.debug.flags.nil? or not @config.debug.flags.include?(:debug_nomaildeletion)
-      @imap.store(@message_id, "+FLAGS", [:Deleted])
-	end
+        if @config.debug.nil? or @config.debug.flags.nil? or not @config.debug.flags.include?(:debug_nomaildeletion)
+          @imap.store(@message_id, "+FLAGS", [:Deleted])
+        end
       end
     end
 
@@ -132,23 +135,23 @@ module CyborgHood
       true
     end
 
-    def check_mails_once(&message_handler)
-      connect &&
-          authenticate &&
-          check_inbox(&message_handler)
-      if  @imap.capability.include?("IDLE")
-        logger.debug "Waiting for new mails in idle mode"
-        @imap.idle do |resp|
-          if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"
-            message_id = resp.data
-            logger.debug "*** Received mail ##{message_id}"
-            # TODO: can't do that, a new IMAP connection should be used, this one is dedicated to IDLE mode
-            message_handler.call IMAPMessage.new(@imap, message_id)
+    def listen_to_events
+      @imap.add_response_handler do |resp|
+        if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"
+          @available_mails_mutex.synchronize do
+            @available_mails = resp.data.to_i
+            logger.debug "*** Received new mails (#{@available_mails})" if @available_mails > 0
           end
         end
-        sleep(1) until @stop_mail_check
-        @imap.idle_done
       end
+      true
+    end
+
+    def check_mails_once(&message_handler)
+      connect &&
+        authenticate &&
+        listen_to_events &&
+        wait_and_read_mails(&message_handler)
     rescue SocketError, Net::IMAP::NoResponseError => e
       logger.warn "IMAP or Network error: " + e.message
     rescue Net::IMAP::Error => e
@@ -160,6 +163,35 @@ module CyborgHood
       end
     end
 
+    def remaining_mails
+      nb = nil
+      @available_mails_mutex.synchronize do
+        nb = @available_mails
+      end
+      nb
+    end
+
+    def waiting_mails?
+      remaining_mails > 0
+    end
+
+    def wait_and_read_mails(&message_handler)
+      until @stop_mail_check
+        begin
+          check_inbox(&message_handler)
+          # don't loop forever
+          return if not (@config.debug.nil? or @config.debug.flags.nil?) and @config.debug.flags.include?(:debug_nomaildeletion)
+        end while waiting_mails?
+
+        if  @imap.capability.include?("IDLE")
+          logger.debug "Waiting for new mails in idle mode"
+          @imap.idle #do |resp|
+          sleep(1) until @stop_mail_check or waiting_mails?
+          @imap.idle_done
+        end
+      end
+    end
+
     def check_mails(&message_handler)
       @stop_mail_check = false
       until @stop_mail_check
@@ -200,7 +232,6 @@ module CyborgHood
       end
       logger.debug "Mail check finished"
 
-      # TODO: expunge after <n> mails processed in IDLE mode
       @imap.expunge
     end
 
