From ae91976d561e3855753b936fa9ac6048f64e30bd Mon Sep 17 00:00:00 2001 From: shugo Date: Wed, 26 Jul 2017 07:47:34 +0000 Subject: [PATCH] lib/net/imap.rb: support CHANGEDSINCE and MODSEQ Patch by plehoux (Philippe-Antoine Lehoux). [ruby-core:64272] [Feature #10119] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59424 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/net/imap.rb | 53 ++++++++++++++++++---- test/net/imap/test_imap_response_parser.rb | 7 +++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 3f8794cac0..dc185183cd 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -814,13 +814,13 @@ module Net # #=> "12-Oct-2000 22:40:59 +0900" # p data.attr["UID"] # #=> 98 - def fetch(set, attr) - return fetch_internal("FETCH", set, attr) + def fetch(set, attr, mod = nil) + return fetch_internal("FETCH", set, attr, mod) end # Similar to #fetch(), but +set+ contains unique identifiers. - def uid_fetch(set, attr) - return fetch_internal("UID FETCH", set, attr) + def uid_fetch(set, attr, mod = nil) + return fetch_internal("UID FETCH", set, attr, mod) end # Sends a STORE command to alter data associated with messages @@ -1304,8 +1304,12 @@ module Net when Integer NumValidator.ensure_number(data) when Array - data.each do |i| - validate_data(i) + if data[0] == 'CHANGEDSINCE' + NumValidator.ensure_mod_sequence_value(data[1]) + else + data.each do |i| + validate_data(i) + end end when Time when Symbol @@ -1417,7 +1421,7 @@ module Net end end - def fetch_internal(cmd, set, attr) + def fetch_internal(cmd, set, attr, mod = nil) case attr when String then attr = RawData.new(attr) @@ -1429,7 +1433,11 @@ module Net synchronize do @responses.delete("FETCH") - send_command(cmd, MessageSet.new(set), attr) + if mod + send_command(cmd, MessageSet.new(set), attr, mod) + else + send_command(cmd, MessageSet.new(set), attr) + end return @responses.delete("FETCH") end end @@ -1663,6 +1671,15 @@ module Net num != 0 && valid_number?(num) end + # Check is passed argument valid 'mod_sequence_value' in RFC 4551 terminology + def valid_mod_sequence_value?(num) + # mod-sequence-value = 1*DIGIT + # ; Positive unsigned 64-bit integer + # ; (mod-sequence) + # ; (1 <= n < 18,446,744,073,709,551,615) + num >= 1 && num < 18446744073709551615 + end + # Ensure argument is 'number' or raise DataFormatError def ensure_number(num) return if valid_number?(num) @@ -1678,6 +1695,14 @@ module Net msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}" raise DataFormatError, msg end + + # Ensure argument is 'mod_sequence_value' or raise DataFormatError + def ensure_mod_sequence_value(num) + return if valid_mod_sequence_value?(num) + + msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}" + raise DataFormatError, msg + end end end @@ -2343,6 +2368,8 @@ module Net name, val = body_data when /\A(?:UID)\z/ni name, val = uid_data + when /\A(?:MODSEQ)\z/ni + name, val = modseq_data else parse_error("unknown attribute `%s' for {%d}", token.value, n) end @@ -2832,6 +2859,16 @@ module Net return name, number end + def modseq_data + token = match(T_ATOM) + name = token.value.upcase + match(T_SPACE) + match(T_LPAR) + modseq = number + match(T_RPAR) + return name, modseq + end + def text_response token = match(T_ATOM) name = token.value.upcase diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb index 3ebb248b4e..b8c6db86cd 100644 --- a/test/net/imap/test_imap_response_parser.rb +++ b/test/net/imap/test_imap_response_parser.rb @@ -304,4 +304,11 @@ EOF assert_equal("INBOX", response.data.mailbox) assert_equal(1234, response.data.attr["UIDVALIDITY"]) end + + # [Bug #10119] + def test_msg_att_modseq_data + parser = Net::IMAP::ResponseParser.new + response = parser.parse("* 1 FETCH (FLAGS (\Seen) MODSEQ (12345) UID 5)\r\n") + assert_equal(12345, response.data.attr["MODSEQ"]) + end end