Skip to content

Commit eb8e65c

Browse files
authored
🔀 Merge pull request #203 from ruby/parser/rewrite-response_data
♻️ Refactor `response-data` methods to match ABNF
2 parents a82f790 + b174f22 commit eb8e65c

File tree

1 file changed

+83
-48
lines changed

1 file changed

+83
-48
lines changed

lib/net/imap/response_parser.rb

Lines changed: 83 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -383,15 +383,20 @@ def label(word)
383383
parse_error("unexpected atom %p, expected %p instead", val, word)
384384
end
385385

386+
# expects "OK" or "PREAUTH" and raises InvalidResponseError on failure
387+
def resp_cond_auth__name
388+
lbl = tagged_ext_label and AUTH_CONDS.include? lbl and return lbl
389+
raise InvalidResponseError, "bad response type %p, expected %s" % [
390+
lbl, AUTH_CONDS.join(" or ")
391+
]
392+
end
393+
386394
# expects "OK" or "NO" or "BAD" and raises InvalidResponseError on failure
387395
def resp_cond_state__name
388-
if RESP_COND_STATES.include?(actual = tagged_ext_label)
389-
actual
390-
else
391-
raise InvalidResponseError, "bad response type %p, expected %s" % [
392-
actual, RESP_COND_STATES.join(" or ")
393-
]
394-
end
396+
lbl = tagged_ext_label and RESP_COND_STATES.include? lbl and return lbl
397+
raise InvalidResponseError, "bad response type %p, expected %s" % [
398+
lbl, RESP_COND_STATES.join(" or ")
399+
]
395400
end
396401

397402
# nstring = string / nil
@@ -487,45 +492,45 @@ def response_data
487492
STAR!; SP!
488493
m = peek_re(RE_RESPONSE_TYPE) or parse_error("unparsable response")
489494
case m["type"].upcase
490-
when "OK" then response_cond # RFC3501, RFC9051
495+
when "OK" then resp_cond_state__untagged # RFC3501, RFC9051
491496
when "FETCH" then message_data__fetch # RFC3501, RFC9051
492497
when "EXPUNGE" then message_data__expunge # RFC3501, RFC9051
493498
when "EXISTS" then mailbox_data__exists # RFC3501, RFC9051
494499
when "ESEARCH" then esearch_response # RFC4731, RFC9051, etc
495500
when "VANISHED" then expunged_resp # RFC7162
496501
when "UIDFETCH" then uidfetch_resp # (draft) UIDONLY
497-
when "SEARCH" then search_response # RFC3501 (obsolete)
502+
when "SEARCH" then mailbox_data__search # RFC3501 (obsolete)
498503
when "CAPABILITY" then capability_data__untagged # RFC3501, RFC9051
499-
when "FLAGS" then flags_response # RFC3501, RFC9051
500-
when "LIST" then list_response # RFC3501, RFC9051
501-
when "STATUS" then status_response # RFC3501, RFC9051
504+
when "FLAGS" then mailbox_data__flags # RFC3501, RFC9051
505+
when "LIST" then mailbox_data__list # RFC3501, RFC9051
506+
when "STATUS" then mailbox_data__status # RFC3501, RFC9051
502507
when "NAMESPACE" then namespace_response # RFC2342, RFC9051
503508
when "ENABLED" then enable_data # RFC5161, RFC9051
504-
when "BAD" then response_cond # RFC3501, RFC9051
505-
when "NO" then response_cond # RFC3501, RFC9051
506-
when "PREAUTH" then response_cond # RFC3501, RFC9051
507-
when "BYE" then response_cond # RFC3501, RFC9051
509+
when "BAD" then resp_cond_state__untagged # RFC3501, RFC9051
510+
when "NO" then resp_cond_state__untagged # RFC3501, RFC9051
511+
when "PREAUTH" then resp_cond_auth # RFC3501, RFC9051
512+
when "BYE" then resp_cond_bye # RFC3501, RFC9051
508513
when "RECENT" then mailbox_data__recent # RFC3501 (obsolete)
509514
when "SORT" then sort_data # RFC5256, RFC7162
510-
when "THREAD" then thread_response # RFC5256
511-
when "QUOTA" then getquota_response # RFC2087, RFC9208
512-
when "QUOTAROOT" then getquotaroot_response # RFC2087, RFC9208
515+
when "THREAD" then thread_data # RFC5256
516+
when "QUOTA" then quota_response # RFC2087, RFC9208
517+
when "QUOTAROOT" then quotaroot_response # RFC2087, RFC9208
513518
when "ID" then id_response # RFC2971
514-
when "ACL" then getacl_response # RFC4314
519+
when "ACL" then acl_data # RFC4314
515520
when "LISTRIGHTS" then listrights_data # RFC4314
516521
when "MYRIGHTS" then myrights_data # RFC4314
517522
when "METADATA" then metadata_resp # RFC5464
518523
when "LANGUAGE" then language_data # RFC5255
519524
when "COMPARATOR" then comparator_data # RFC5255
520525
when "CONVERTED" then message_data__converted # RFC5259
521-
when "LSUB" then list_response # RFC3501 (obsolete)
522-
when "XLIST" then list_response # deprecated
523-
when "NOOP" then ignored_response
524-
else unparsed_response
526+
when "LSUB" then mailbox_data__lsub # RFC3501 (obsolete)
527+
when "XLIST" then mailbox_data__xlist # deprecated
528+
when "NOOP" then response_data__noop
529+
else response_data__unhandled
525530
end
526531
end
527532

528-
def unparsed_response(klass = UntaggedResponse)
533+
def response_data__unhandled(klass = UntaggedResponse)
529534
num = number?; SP?
530535
type = tagged_ext_label; SP?
531536
text = remaining_unparsed
@@ -539,17 +544,18 @@ def remaining_unparsed
539544
str&.empty? ? nil : str
540545
end
541546

542-
def ignored_response; unparsed_response(IgnoredResponse) end
547+
def response_data__ignored; response_data__unhandled(IgnoredResponse) end
548+
alias response_data__noop response_data__ignored
543549

544-
alias esearch_response unparsed_response
545-
alias expunged_resp unparsed_response
546-
alias uidfetch_resp unparsed_response
547-
alias listrights_data unparsed_response
548-
alias myrights_data unparsed_response
549-
alias metadata_resp unparsed_response
550-
alias language_data unparsed_response
551-
alias comparator_data unparsed_response
552-
alias message_data__converted unparsed_response
550+
alias esearch_response response_data__unhandled
551+
alias expunged_resp response_data__unhandled
552+
alias uidfetch_resp response_data__unhandled
553+
alias listrights_data response_data__unhandled
554+
alias myrights_data response_data__unhandled
555+
alias metadata_resp response_data__unhandled
556+
alias language_data response_data__unhandled
557+
alias comparator_data response_data__unhandled
558+
alias message_data__converted response_data__unhandled
553559

554560
# RFC3501 & RFC9051:
555561
# response-tagged = tag SP resp-cond-state CRLF
@@ -561,15 +567,26 @@ def ignored_response; unparsed_response(IgnoredResponse) end
561567
def response_tagged
562568
tag = tag(); SP!
563569
name = resp_cond_state__name; SP!
564-
data = resp_text
565-
TaggedResponse.new(tag, name, data, @str)
570+
TaggedResponse.new(tag, name, resp_text, @str)
566571
end
567572

568-
def response_cond
569-
token = match(T_ATOM)
570-
name = token.value.upcase
571-
match(T_SPACE)
572-
return UntaggedResponse.new(name, resp_text, @str)
573+
# RFC3501 & RFC9051:
574+
# resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
575+
def resp_cond_state__untagged
576+
name = resp_cond_state__name; SP!
577+
UntaggedResponse.new(name, resp_text, @str)
578+
end
579+
580+
# resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
581+
def resp_cond_auth
582+
name = resp_cond_auth__name; SP!
583+
UntaggedResponse.new(name, resp_text, @str)
584+
end
585+
586+
# resp-cond-bye = "BYE" SP resp-text
587+
def resp_cond_bye
588+
name = label(BYE); SP!
589+
UntaggedResponse.new(name, resp_text, @str)
573590
end
574591

575592
# message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
@@ -1046,19 +1063,21 @@ def modseq_data
10461063
return name, modseq
10471064
end
10481065

1049-
def flags_response
1066+
def mailbox_data__flags
10501067
token = match(T_ATOM)
10511068
name = token.value.upcase
10521069
match(T_SPACE)
10531070
return UntaggedResponse.new(name, flag_list, @str)
10541071
end
10551072

1056-
def list_response
1073+
def mailbox_data__list
10571074
token = match(T_ATOM)
10581075
name = token.value.upcase
10591076
match(T_SPACE)
10601077
return UntaggedResponse.new(name, mailbox_list, @str)
10611078
end
1079+
alias mailbox_data__lsub mailbox_data__list
1080+
alias mailbox_data__xlist mailbox_data__list
10621081

10631082
def mailbox_list
10641083
attr = flag_list
@@ -1124,7 +1143,8 @@ def getquotaroot_response
11241143
return UntaggedResponse.new(name, data, @str)
11251144
end
11261145

1127-
def getacl_response
1146+
# acl-data = "ACL" SP mailbox *(SP identifier SP rights)
1147+
def acl_data
11281148
token = match(T_ATOM)
11291149
name = token.value.upcase
11301150
match(T_SPACE)
@@ -1150,7 +1170,21 @@ def getacl_response
11501170
return UntaggedResponse.new(name, data, @str)
11511171
end
11521172

1153-
def search_response
1173+
# RFC3501:
1174+
# mailbox-data = "SEARCH" *(SP nz-number) / ...
1175+
# RFC5256: SORT
1176+
# sort-data = "SORT" *(SP nz-number)
1177+
# RFC7162: CONDSTORE, QRESYNC
1178+
# mailbox-data =/ "SEARCH" [1*(SP nz-number) SP
1179+
# search-sort-mod-seq]
1180+
# sort-data = "SORT" [1*(SP nz-number) SP
1181+
# search-sort-mod-seq]
1182+
# ; Updates the SORT response from RFC 5256.
1183+
# search-sort-mod-seq = "(" "MODSEQ" SP mod-sequence-value ")"
1184+
# RFC9051:
1185+
# mailbox-data = obsolete-search-response / ...
1186+
# obsolete-search-response = "SEARCH" *(SP nz-number)
1187+
def mailbox_data__search
11541188
token = match(T_ATOM)
11551189
name = token.value.upcase
11561190
token = lookahead
@@ -1180,8 +1214,9 @@ def search_response
11801214
end
11811215
return UntaggedResponse.new(name, data, @str)
11821216
end
1217+
alias sort_data mailbox_data__search
11831218

1184-
def thread_response
1219+
def thread_data
11851220
token = match(T_ATOM)
11861221
name = token.value.upcase
11871222
token = lookahead
@@ -1243,7 +1278,7 @@ def thread_branch(token)
12431278
return rootmember
12441279
end
12451280

1246-
def status_response
1281+
def mailbox_data__status
12471282
token = match(T_ATOM)
12481283
name = token.value.upcase
12491284
match(T_SPACE)

0 commit comments

Comments
 (0)