From 4676ede3d1338ca78c58496a3ce11e78df188215 Mon Sep 17 00:00:00 2001 From: shugo Date: Thu, 23 Jul 2009 15:20:47 +0000 Subject: [PATCH] * lib/net/imap.rb (resp_text_code): accepts response codes without text. [ruby-core:24194] * lib/net/imap.rb (idle, idle_done): new methods for the IMAP4 IDLE command (RFC 2177). Thanks, Eric Hodel. * lib/net/imap.rb (format_date, format_datetime): new method to format IMAP-style date/datetime. Thanks, Eric Hodel. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24259 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 11 +++++++ lib/net/imap.rb | 60 ++++++++++++++++++++++++++++++++--- test/net/imap/test_imap.rb | 64 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 938501b8d7..2a5d02a08c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Fri Jul 24 00:13:41 2009 Shugo Maeda + + * lib/net/imap.rb (resp_text_code): accepts response codes without + text. [ruby-core:24194] + + * lib/net/imap.rb (idle, idle_done): new methods for the IMAP4 IDLE + command (RFC 2177). Thanks, Eric Hodel. + + * lib/net/imap.rb (format_date, format_datetime): new method to + format IMAP-style date/datetime. Thanks, Eric Hodel. + Thu Jul 23 17:31:02 2009 Keiju Ishitsuka * lib/irb/ruby-lex.rb: make irb be able to parse diff --git a/lib/net/imap.rb b/lib/net/imap.rb index e67c294464..5741568034 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -838,6 +838,41 @@ module Net return thread_internal("UID THREAD", algorithm, search_keys, charset) end + # Sends an IDLE command that waits for notifications of new or expunged + # messages. Yields responses from the server during the IDLE. + # + # Use #idle_done() to leave IDLE. + def idle(&response_handler) + raise LocalJumpError, "no block given" unless response_handler + + response = nil + + synchronize do + tag = Thread.current[:net_imap_tag] = generate_tag + put_string("#{tag} IDLE#{CRLF}") + + add_response_handler(response_handler) + @idle_done_cond = new_cond + @idle_done_cond.wait + @idle_done_cond = nil + remove_response_handler(response_handler) + put_string("DONE#{CRLF}") + response = get_tagged_response(tag, "IDLE") + end + + return response + end + + # Leaves IDLE. + def idle_done + if @idle_done_cond.nil? + raise Net::IMAP::Error, "not during IDLE" + end + synchronize do + @idle_done_cond.signal + end + end + # Decode a string from modified UTF-7 format to UTF-8. # # UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a @@ -873,6 +908,16 @@ module Net }.force_encoding("ASCII-8BIT") end + # Formats +time+ as an IMAP-style date. + def self.format_date(time) + return time.strftime('%d-%b-%Y') + end + + # Formats +time+ as an IMAP-style date-time. + def self.format_datetime(time) + return time.strftime('%d-%b-%Y %H:%M %z') + end + private CRLF = "\r\n" # :nodoc: @@ -2776,11 +2821,16 @@ module Net match(T_SPACE) result = ResponseCode.new(name, number) else - match(T_SPACE) - @lex_state = EXPR_CTEXT - token = match(T_TEXT) - @lex_state = EXPR_BEG - result = ResponseCode.new(name, token.value) + token = lookahead + if token.symbol == T_SPACE + shift_token + @lex_state = EXPR_CTEXT + token = match(T_TEXT) + @lex_state = EXPR_BEG + result = ResponseCode.new(name, token.value) + else + result = ResponseCode.new(name, nil) + end end match(T_RBRA) @lex_state = EXPR_RTEXT diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb index cff09d3cbc..e4e1c25ca0 100644 --- a/test/net/imap/test_imap.rb +++ b/test/net/imap/test_imap.rb @@ -18,6 +18,18 @@ class IMAPTest < Test::Unit::TestCase assert_equal(utf8, s) end + def test_format_date + time = Time.mktime(2009, 7, 24) + s = Net::IMAP.format_date(time) + assert_equal("24-Jul-2009", s) + end + + def test_format_datetime + time = Time.mktime(2009, 7, 24, 1, 23, 45) + s = Net::IMAP.format_datetime(time) + assert_match(/\A24-Jul-2009 01:23 [+\-]\d{4}\z/, s) + end + def test_imaps_unknown_ca if defined?(OpenSSL) assert_raise(OpenSSL::SSL::SSLError) do @@ -112,6 +124,58 @@ class IMAPTest < Test::Unit::TestCase end end + def test_idle + server = TCPServer.new(0) + port = server.addr[1] + requests = [] + Thread.start do + begin + sock = server.accept + begin + sock.print("* OK test server\r\n") + requests.push(sock.gets) + sock.print("+ idling\r\n") + sock.print("* 3 EXISTS\r\n") + sock.print("* 2 EXPUNGE\r\n") + requests.push(sock.gets) + sock.print("RUBY0001 OK IDLE terminated\r\n") + sock.gets + sock.print("* BYE terminating connection\r\n") + sock.print("RUBY0002 OK LOGOUT completed\r\n") + ensure + sock.close + end + rescue + end + end + begin + begin + imap = Net::IMAP.new("localhost", :port => port) + responses = [] + imap.idle do |res| + responses.push(res) + if res.name == "EXPUNGE" + imap.idle_done + end + end + assert_equal(3, responses.length) + assert_instance_of(Net::IMAP::ContinuationRequest, responses[0]) + assert_equal("EXISTS", responses[1].name) + assert_equal(3, responses[1].data) + assert_equal("EXPUNGE", responses[2].name) + assert_equal(2, responses[2].data) + assert_equal(2, requests.length) + assert_equal("RUBY0001 IDLE\r\n", requests[0]) + assert_equal("DONE\r\n", requests[1]) + imap.logout + ensure + imap.disconnect if imap + end + ensure + server.close + end + end + private def imaps_test