Skip to content

Commit ef38f8e

Browse files
committed
⚡️ Separate msg-att parsing for labels and values
Read entire attr label for `BODY[...]<...>` prior to case stmt. This greatly simplifies the code for reading each attribute value, allowing much of it to be deleted.
1 parent a659700 commit ef38f8e

File tree

1 file changed

+54
-87
lines changed

1 file changed

+54
-87
lines changed

lib/net/imap/response_parser.rb

Lines changed: 54 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,17 @@ def case_insensitive__nstring
427427
alias nz_number number
428428
alias nz_number? number?
429429

430+
# valid number ranges are not enforced by parser
431+
# nz-number64 = digit-nz *DIGIT
432+
# ; Unsigned 63-bit integer
433+
# ; (0 < n <= 9,223,372,036,854,775,807)
434+
alias nz_number64 nz_number
435+
436+
# valid number ranges are not enforced by parser
437+
# uniqueid = nz-number
438+
# ; Strictly ascending
439+
alias uniqueid nz_number
440+
430441
# [RFC3501 & RFC9051:]
431442
# response = *(continue-req / response-data) response-done
432443
#
@@ -658,20 +669,21 @@ def msg_att(n)
658669
lpar
659670
attr = {}
660671
while true
661-
name = lookahead!(T_ATOM).value.upcase
662-
name, val =
672+
name = msg_att__label; SP!
673+
val =
663674
case name
664-
when "UID" then uid_data
665-
when "FLAGS" then flags_data
666-
when "BODY" then body_data
667-
when "BODYSTRUCTURE" then body_data
668-
when "ENVELOPE" then envelope_data
669-
when "INTERNALDATE" then internaldate_data
670-
when "RFC822.SIZE" then rfc822_size
671-
when "RFC822" then rfc822_text
672-
when "RFC822.HEADER" then rfc822_text # not in rev2
673-
when "RFC822.TEXT" then rfc822_text # not in rev2
674-
when "MODSEQ" then modseq_data # CONDSTORE
675+
when "UID" then uniqueid
676+
when "FLAGS" then flag_list
677+
when "BODY" then body
678+
when /\ABODY\[/ni then nstring
679+
when "BODYSTRUCTURE" then body
680+
when "ENVELOPE" then envelope
681+
when "INTERNALDATE" then date_time
682+
when "RFC822.SIZE" then number64
683+
when "RFC822" then nstring # not in rev2
684+
when "RFC822.HEADER" then nstring # not in rev2
685+
when "RFC822.TEXT" then nstring # not in rev2
686+
when "MODSEQ" then parens__modseq # CONDSTORE
675687
else parse_error("unknown attribute `%s' for {%d}", name, n)
676688
end
677689
attr[name] = val
@@ -682,11 +694,17 @@ def msg_att(n)
682694
attr
683695
end
684696

685-
def envelope_data
686-
token = match(T_ATOM)
687-
name = token.value.upcase
688-
match(T_SPACE)
689-
return name, envelope
697+
# appends "[section]" and "<partial>" to the base label
698+
def msg_att__label
699+
case (name = tagged_ext_label)
700+
when /\A(?:RFC822(?:\.HEADER|\.TEXT)?)\z/ni
701+
# ignoring "[]" fixes https://bugs.ruby-lang.org/issues/5620
702+
lbra? and rbra
703+
when "BODY"
704+
peek_lbra? and name << section and
705+
peek_str?("<") and name << atom # partial
706+
end
707+
name
690708
end
691709

692710
def envelope
@@ -724,58 +742,10 @@ def envelope
724742
return result
725743
end
726744

727-
def flags_data
728-
token = match(T_ATOM)
729-
name = token.value.upcase
730-
match(T_SPACE)
731-
return name, flag_list
732-
end
733-
734-
def internaldate_data
735-
token = match(T_ATOM)
736-
name = token.value.upcase
737-
match(T_SPACE)
738-
token = match(T_QUOTED)
739-
return name, token.value
740-
end
741-
742-
def rfc822_text
743-
token = match(T_ATOM)
744-
name = token.value.upcase
745-
token = lookahead
746-
if token.symbol == T_LBRA
747-
shift_token
748-
match(T_RBRA)
749-
end
750-
match(T_SPACE)
751-
return name, nstring
752-
end
753-
754-
def rfc822_size
755-
token = match(T_ATOM)
756-
name = token.value.upcase
757-
match(T_SPACE)
758-
return name, number
759-
end
760-
761-
def body_data
762-
token = match(T_ATOM)
763-
name = token.value.upcase
764-
token = lookahead
765-
if token.symbol == T_SPACE
766-
shift_token
767-
return name, body
768-
end
769-
name.concat(section)
770-
token = lookahead
771-
if token.symbol == T_ATOM
772-
name.concat(token.value)
773-
shift_token
774-
end
775-
match(T_SPACE)
776-
data = nstring
777-
return name, data
778-
end
745+
# date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
746+
# SP time SP zone DQUOTE
747+
alias date_time quoted
748+
alias ndatetime nquoted
779749

780750
# RFC-3501 & RFC-9051:
781751
# body = "(" (body-type-1part / body-type-mpart) ")"
@@ -1114,23 +1084,6 @@ def header_fld_name
11141084
end
11151085
end
11161086

1117-
def uid_data
1118-
token = match(T_ATOM)
1119-
name = token.value.upcase
1120-
match(T_SPACE)
1121-
return name, number
1122-
end
1123-
1124-
def modseq_data
1125-
token = match(T_ATOM)
1126-
name = token.value.upcase
1127-
match(T_SPACE)
1128-
match(T_LPAR)
1129-
modseq = number
1130-
match(T_RPAR)
1131-
return name, modseq
1132-
end
1133-
11341087
def mailbox_data__flags
11351088
token = match(T_ATOM)
11361089
name = token.value.upcase
@@ -1698,6 +1651,20 @@ def charset
16981651
end
16991652
end
17001653

1654+
# RFC7162:
1655+
# mod-sequence-value = 1*DIGIT
1656+
# ;; Positive unsigned 63-bit integer
1657+
# ;; (mod-sequence)
1658+
# ;; (1 <= n <= 9,223,372,036,854,775,807).
1659+
alias mod_sequence_value nz_number64
1660+
1661+
# RFC7162:
1662+
# permsg-modsequence = mod-sequence-value
1663+
# ;; Per-message mod-sequence.
1664+
alias permsg_modsequence mod_sequence_value
1665+
1666+
def parens__modseq; lpar; _ = permsg_modsequence; rpar; _ end
1667+
17011668
# RFC-4315 (UIDPLUS) or RFC9051 (IMAP4rev2):
17021669
# uid-set = (uniqueid / uid-range) *("," uid-set)
17031670
# uid-range = (uniqueid ":" uniqueid)

0 commit comments

Comments
 (0)