@@ -1346,11 +1346,13 @@ def enable_data
13461346 end
13471347
13481348 # As a workaround for buggy servers, allow a trailing SP:
1349- # *(SP capapility ) [SP]
1349+ # *(SP capability ) [SP]
13501350 def capability__list
1351- data = [ ] ; while _ = SP? && capability? do data << _ end ; data
1351+ list = [ ] ; while SP? && ( capa = capability? ) do list << capa end ; list
13521352 end
13531353
1354+ alias resp_code__capability capability__list
1355+
13541356 # capability = ("AUTH=" auth-type) / atom
13551357 # ; New capabilities MUST begin with "X" or be
13561358 # ; registered with IANA as standard or
@@ -1473,68 +1475,91 @@ def resp_text
14731475 end
14741476 end
14751477
1476- # See https://www.rfc-editor.org/errata/rfc3501
1478+ # RFC3501 (See https://www.rfc-editor.org/errata/rfc3501):
1479+ # resp-text-code = "ALERT" /
1480+ # "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
1481+ # capability-data / "PARSE" /
1482+ # "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" /
1483+ # "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
1484+ # "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
1485+ # "UNSEEN" SP nz-number /
1486+ # atom [SP 1*<any TEXT-CHAR except "]">]
1487+ # capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
1488+ # *(SP capability)
1489+ #
1490+ # RFC5530:
1491+ # resp-text-code =/ "UNAVAILABLE" / "AUTHENTICATIONFAILED" /
1492+ # "AUTHORIZATIONFAILED" / "EXPIRED" /
1493+ # "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" /
1494+ # "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" /
1495+ # "SERVERBUG" / "CLIENTBUG" / "CANNOT" /
1496+ # "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" /
1497+ # "NONEXISTENT"
1498+ # RFC9051:
1499+ # resp-text-code = "ALERT" /
1500+ # "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
1501+ # capability-data / "PARSE" /
1502+ # "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" /
1503+ # "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
1504+ # "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
1505+ # resp-code-apnd / resp-code-copy / "UIDNOTSTICKY" /
1506+ # "UNAVAILABLE" / "AUTHENTICATIONFAILED" /
1507+ # "AUTHORIZATIONFAILED" / "EXPIRED" /
1508+ # "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" /
1509+ # "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" /
1510+ # "SERVERBUG" / "CLIENTBUG" / "CANNOT" /
1511+ # "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" /
1512+ # "NONEXISTENT" / "NOTSAVED" / "HASCHILDREN" /
1513+ # "CLOSED" /
1514+ # "UNKNOWN-CTE" /
1515+ # atom [SP 1*<any TEXT-CHAR except "]">]
1516+ # capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev2"
1517+ # *(SP capability)
14771518 #
1478- # resp-text-code = "ALERT" /
1479- # "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
1480- # capability-data / "PARSE" /
1481- # "PERMANENTFLAGS" SP "("
1482- # [flag-perm *(SP flag-perm)] ")" /
1483- # "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
1484- # "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
1485- # "UNSEEN" SP nz-number /
1486- # atom [SP 1*<any TEXT-CHAR except "]">]
1519+ # RFC4315 (UIDPLUS), RFC9051 (IMAP4rev2):
1520+ # resp-code-apnd = "APPENDUID" SP nz-number SP append-uid
1521+ # resp-code-copy = "COPYUID" SP nz-number SP uid-set SP uid-set
1522+ # resp-text-code =/ resp-code-apnd / resp-code-copy / "UIDNOTSTICKY"
14871523 #
1488- # +UIDPLUS+ ABNF:: https://www.rfc-editor.org/rfc/rfc4315.html#section-4
1489- # resp-text-code =/ resp-code-apnd / resp-code-copy / "UIDNOTSTICKY"
1524+ # RFC7162 (CONDSTORE):
1525+ # resp-text-code =/ "HIGHESTMODSEQ" SP mod-sequence-value /
1526+ # "NOMODSEQ" /
1527+ # "MODIFIED" SP sequence-set
14901528 def resp_text_code
1491- token = match ( T_ATOM )
1492- name = token . value . upcase
1493- case name
1494- when /\A (?:ALERT|PARSE|READ-ONLY|READ-WRITE|TRYCREATE|NOMODSEQ)\z /n
1495- result = ResponseCode . new ( name , nil )
1496- when /\A (?:BADCHARSET)\z /n
1497- result = ResponseCode . new ( name , charset_list )
1498- when /\A (?:CAPABILITY)\z /ni
1499- result = ResponseCode . new ( name , capability__list )
1500- when /\A (?:PERMANENTFLAGS)\z /n
1501- match ( T_SPACE )
1502- result = ResponseCode . new ( name , flag_list )
1503- when /\A (?:UIDVALIDITY|UIDNEXT|UNSEEN)\z /n
1504- match ( T_SPACE )
1505- result = ResponseCode . new ( name , number )
1506- when /\A (?:APPENDUID)\z /n
1507- result = ResponseCode . new ( name , resp_code_apnd__data )
1508- when /\A (?:COPYUID)\z /n
1509- result = ResponseCode . new ( name , resp_code_copy__data )
1510- else
1511- token = lookahead
1512- if token . symbol == T_SPACE
1513- shift_token
1514- result = ResponseCode . new ( name , text_chars_except_rbra )
1529+ name = resp_text_code__name
1530+ data =
1531+ case name
1532+ when "CAPABILITY" then resp_code__capability
1533+ when "PERMANENTFLAGS" then SP? ? flag_perm__list : [ ]
1534+ when "UIDNEXT" then SP! ; nz_number
1535+ when "UIDVALIDITY" then SP! ; nz_number
1536+ when "UNSEEN" then SP! ; nz_number # rev1 only
1537+ when "APPENDUID" then SP! ; resp_code_apnd__data # rev2, UIDPLUS
1538+ when "COPYUID" then SP! ; resp_code_copy__data # rev2, UIDPLUS
1539+ when "BADCHARSET" then SP? ? charset__list : [ ]
1540+ when "ALERT" , "PARSE" , "READ-ONLY" , "READ-WRITE" , "TRYCREATE" ,
1541+ "UNAVAILABLE" , "AUTHENTICATIONFAILED" , "AUTHORIZATIONFAILED" ,
1542+ "EXPIRED" , "PRIVACYREQUIRED" , "CONTACTADMIN" , "NOPERM" , "INUSE" ,
1543+ "EXPUNGEISSUED" , "CORRUPTION" , "SERVERBUG" , "CLIENTBUG" , "CANNOT" ,
1544+ "LIMIT" , "OVERQUOTA" , "ALREADYEXISTS" , "NONEXISTENT" , "CLOSED" ,
1545+ "NOTSAVED" , "UIDNOTSTICKY" , "UNKNOWN-CTE" , "HASCHILDREN"
1546+ when "NOMODSEQ" # CONDSTORE
15151547 else
1516- result = ResponseCode . new ( name , nil )
1548+ SP? and text_chars_except_rbra
15171549 end
1518- end
1519- return result
1550+ ResponseCode . new ( name , data )
15201551 end
15211552
1553+ alias resp_text_code__name case_insensitive__atom
1554+
15221555 # 1*<any TEXT-CHAR except "]">
15231556 def text_chars_except_rbra
15241557 match_re ( CTEXT_REGEXP , '1*<any TEXT-CHAR except "]">' ) [ 0 ]
15251558 end
15261559
1527- def charset_list
1528- result = [ ]
1529- if accept ( T_SPACE )
1530- match ( T_LPAR )
1531- result << charset
1532- while accept ( T_SPACE )
1533- result << charset
1534- end
1535- match ( T_RPAR )
1536- end
1537- result
1560+ # "(" charset *(SP charset) ")"
1561+ def charset__list
1562+ lpar ; list = [ charset ] ; while SP? do list << charset end ; rpar ; list
15381563 end
15391564
15401565 # already matched: "APPENDUID"
@@ -1550,18 +1575,18 @@ def charset_list
15501575 # match uid_set even if that returns a single-member array.
15511576 #
15521577 def resp_code_apnd__data
1553- match ( T_SPACE ) ; validity = number
1554- match ( T_SPACE ) ; dst_uids = uid_set # uniqueid ⊂ uid-set
1578+ validity = number ; SP!
1579+ dst_uids = uid_set # uniqueid ⊂ uid-set
15551580 UIDPlusData . new ( validity , nil , dst_uids )
15561581 end
15571582
15581583 # already matched: "COPYUID"
15591584 #
15601585 # resp-code-copy = "COPYUID" SP nz-number SP uid-set SP uid-set
15611586 def resp_code_copy__data
1562- match ( T_SPACE ) ; validity = number
1563- match ( T_SPACE ) ; src_uids = uid_set
1564- match ( T_SPACE ) ; dst_uids = uid_set
1587+ validity = number ; SP!
1588+ src_uids = uid_set ; SP!
1589+ dst_uids = uid_set
15651590 UIDPlusData . new ( validity , src_uids , dst_uids )
15661591 end
15671592
@@ -1639,17 +1664,13 @@ def flag_list
16391664 end
16401665 end
16411666
1667+ # TODO: not quite correct. flag-perm != flag
1668+ alias flag_perm__list flag_list
16421669
16431670 # See https://www.rfc-editor.org/errata/rfc3501
16441671 #
16451672 # charset = atom / quoted
1646- def charset
1647- if token = accept ( T_QUOTED )
1648- token . value
1649- else
1650- atom
1651- end
1652- end
1673+ def charset ; quoted? || atom end
16531674
16541675 # RFC7162:
16551676 # mod-sequence-value = 1*DIGIT
0 commit comments