Skip to content

Commit 9caff31

Browse files
committed
♻️ Refactor to forthcoming updated parser style
* Include ABNF and document any deviations or workarounds. * Methods are all named according to the pattern: ```ruby [modifier, grammar_rule.tr("-", "_"), subrule].join("__") ``` * This does change the behavior to only accept a single SP token betwwen each listed capability, but I don't think I've seen that particular spec violation.
1 parent 6220067 commit 9caff31

File tree

1 file changed

+29
-27
lines changed

1 file changed

+29
-27
lines changed

lib/net/imap/response_parser.rb

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,11 @@ def response_untagged
199199
when /\A(?:STATUS)\z/ni
200200
return status_response
201201
when /\A(?:CAPABILITY)\z/ni
202-
return capability_response
202+
return capability_data__untagged
203203
when /\A(?:NOOP)\z/ni
204204
return ignored_response
205205
when /\A(?:ENABLED)\z/ni
206-
return enabled_response
206+
return enable_data
207207
else
208208
return text_response
209209
end
@@ -1011,36 +1011,38 @@ def status_response
10111011
return UntaggedResponse.new(name, data, @str)
10121012
end
10131013

1014-
def capability_response
1015-
token = match(T_ATOM)
1016-
name = token.value.upcase
1017-
match(T_SPACE)
1018-
UntaggedResponse.new(name, capability_data, @str)
1014+
# The presence of "IMAP4rev1" or "IMAP4rev2" is unenforced here.
1015+
# The grammar rule is used by both response-data and resp-text-code.
1016+
# But this method only returns UntaggedResponse (response-data).
1017+
#
1018+
# RFC3501:
1019+
# capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
1020+
# *(SP capability)
1021+
# RFC9051:
1022+
# capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev2"
1023+
# *(SP capability)
1024+
def capability_data__untagged
1025+
UntaggedResponse.new label("CAPABILITY"), capability__list, @str
10191026
end
10201027

1021-
def enabled_response
1022-
token = match(T_ATOM)
1023-
name = token.value.upcase
1024-
match(T_SPACE)
1025-
UntaggedResponse.new(name, capability_data, @str)
1028+
# enable-data = "ENABLED" *(SP capability)
1029+
def enable_data
1030+
UntaggedResponse.new label("ENABLED"), capability__list, @str
10261031
end
10271032

1028-
def capability_data
1029-
data = []
1030-
while true
1031-
token = lookahead
1032-
case token.symbol
1033-
when T_CRLF, T_RBRA
1034-
break
1035-
when T_SPACE
1036-
shift_token
1037-
next
1038-
end
1039-
data.push(atom.upcase)
1040-
end
1041-
data
1033+
# As a workaround for buggy servers, allow a trailing SP:
1034+
# *(SP capapility) [SP]
1035+
def capability__list
1036+
data = []; while _ = SP? && capability? do data << _ end; data
10421037
end
10431038

1039+
# capability = ("AUTH=" auth-type) / atom
1040+
# ; New capabilities MUST begin with "X" or be
1041+
# ; registered with IANA as standard or
1042+
# ; standards-track
1043+
alias capability case_insensitive__atom
1044+
alias capability? case_insensitive__atom?
1045+
10441046
def id_response
10451047
token = match(T_ATOM)
10461048
name = token.value.upcase
@@ -1176,7 +1178,7 @@ def resp_text_code
11761178
when /\A(?:BADCHARSET)\z/n
11771179
result = ResponseCode.new(name, charset_list)
11781180
when /\A(?:CAPABILITY)\z/ni
1179-
result = ResponseCode.new(name, capability_data)
1181+
result = ResponseCode.new(name, capability__list)
11801182
when /\A(?:PERMANENTFLAGS)\z/n
11811183
match(T_SPACE)
11821184
result = ResponseCode.new(name, flag_list)

0 commit comments

Comments
 (0)