From ba850faa1b510e34dd4edd6b3f3d61d13687eda6 Mon Sep 17 00:00:00 2001 From: nick evans Date: Wed, 11 Feb 2026 13:16:31 -0500 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20Return=20ResponseText=20from?= =?UTF-8?q?=20`resp-text`=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This bug was introduced in #601, which hasn't been released yet. --- lib/net/imap/response_parser.rb | 2 +- .../fixtures/response_parser/quirky_behaviors.yml | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/net/imap/response_parser.rb b/lib/net/imap/response_parser.rb index 2c1d1dd1..7b616bfa 100644 --- a/lib/net/imap/response_parser.rb +++ b/lib/net/imap/response_parser.rb @@ -1898,7 +1898,7 @@ def resp_text rescue ResponseParseError => error raise if /\buid-set\b/i.match? error.message restore_state state - text + ResponseText.new(nil, text? || "") end # RFC3501 (See https://www.rfc-editor.org/errata/rfc3501): diff --git a/test/net/imap/fixtures/response_parser/quirky_behaviors.yml b/test/net/imap/fixtures/response_parser/quirky_behaviors.yml index f6f3e790..1bef93aa 100644 --- a/test/net/imap/fixtures/response_parser/quirky_behaviors.yml +++ b/test/net/imap/fixtures/response_parser/quirky_behaviors.yml @@ -37,21 +37,20 @@ Microsoft Exchange is issuing an invalid resp-text-code, but net-imap should fallback to `resp-text = text` when resp-text-code fails to parse. - :debug: false # current version of backtracking still prints parse_errors :response: "RUBY0001 OK [Error=\"Microsoft.Exchange.Data.Storage.WrongServerException: Cross Server access is not allowed for mailbox xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\" AuthResultFromPopImapEnd=0 Proxy=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM:1993:SSL MailboxBE=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM Service=Imap4] AUTHENTICATE completed.\r\n" :expected: !ruby/struct:Net::IMAP::TaggedResponse - tag: RUBY0001 + tag: RUBY0001 name: OK - data: '[Error="Microsoft.Exchange.Data.Storage.WrongServerException: Cross Server - access is not allowed for mailbox xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - AuthResultFromPopImapEnd=0 - Proxy=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM:1993:SSL - MailboxBE=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM Service=Imap4] - AUTHENTICATE completed.' + data: !ruby/struct:Net::IMAP::ResponseText + code: + text: '[Error="Microsoft.Exchange.Data.Storage.WrongServerException: Cross Server + access is not allowed for mailbox xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" AuthResultFromPopImapEnd=0 + Proxy=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM:1993:SSL MailboxBE=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM + Service=Imap4] AUTHENTICATE completed.' raw_data: "RUBY0001 OK [Error=\"Microsoft.Exchange.Data.Storage.WrongServerException: Cross Server access is not allowed for mailbox xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\" AuthResultFromPopImapEnd=0 Proxy=XXXXXXXXXXXXX.EURXXXX.PROD.OUTLOOK.COM:1993:SSL From 78c204d20008e16e62f6afdebcc44be333e97a08 Mon Sep 17 00:00:00 2001 From: nick evans Date: Wed, 11 Feb 2026 13:22:11 -0500 Subject: [PATCH 2/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20tighter=20scope?= =?UTF-8?q?=20for=20resp-text=20backtracking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This scopes the backtracking _only_ around the `"[" resp-text-code "]"` case. The `else` clause and the `rescue` fallback can now execute the same code. In addition to reducing duplication of code, this also potentially reduces _work_, since there's no point in rescuing the `else` clause only to try the exact same thing again. --- lib/net/imap/response_parser.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/net/imap/response_parser.rb b/lib/net/imap/response_parser.rb index 7b616bfa..b6fbc264 100644 --- a/lib/net/imap/response_parser.rb +++ b/lib/net/imap/response_parser.rb @@ -1888,16 +1888,16 @@ def text? # We leniently re-interpret this as # resp-text = ["[" resp-text-code "]" [SP [text]] / [text] def resp_text - state = current_state - if lbra? - code = resp_text_code; rbra - ResponseText.new(code, SP? && text? || "") - else - ResponseText.new(nil, text? || "") + begin + state = current_state + if lbra? + code = resp_text_code; rbra + return ResponseText.new(code, SP? && text? || "") + end + rescue ResponseParseError => error + raise if /\buid-set\b/i.match? error.message + restore_state state end - rescue ResponseParseError => error - raise if /\buid-set\b/i.match? error.message - restore_state state ResponseText.new(nil, text? || "") end