@@ -185,6 +185,54 @@ module RFC3629
185
185
CODE_TEXT_CHAR = TEXT_CHAR - RESP_SPECIALS
186
186
CODE_TEXT = /#{ CODE_TEXT_CHAR } +/n
187
187
188
+ # flag = "\Answered" / "\Flagged" / "\Deleted" /
189
+ # "\Seen" / "\Draft" / flag-keyword / flag-extension
190
+ # ; Does not include "\Recent"
191
+ # flag-extension = "\" atom
192
+ # ; Future expansion. Client implementations
193
+ # ; MUST accept flag-extension flags. Server
194
+ # ; implementations MUST NOT generate
195
+ # ; flag-extension flags except as defined by
196
+ # ; a future Standard or Standards Track
197
+ # ; revisions of this specification.
198
+ # flag-keyword = "$MDNSent" / "$Forwarded" / "$Junk" /
199
+ # "$NotJunk" / "$Phishing" / atom
200
+ # flag-perm = flag / "\*"
201
+ #
202
+ # Not checking for max one mbx-list-sflag in the parser.
203
+ # >>>
204
+ # mbx-list-oflag = "\Noinferiors" / child-mbox-flag /
205
+ # "\Subscribed" / "\Remote" / flag-extension
206
+ # ; Other flags; multiple from this list are
207
+ # ; possible per LIST response, but each flag
208
+ # ; can only appear once per LIST response
209
+ # mbx-list-sflag = "\NonExistent" / "\Noselect" / "\Marked" /
210
+ # "\Unmarked"
211
+ # ; Selectability flags; only one per LIST response
212
+ # child-mbox-flag = "\HasChildren" / "\HasNoChildren"
213
+ # ; attributes for the CHILDREN return option, at most
214
+ # ; one possible per LIST response
215
+ FLAG = /\\ ?#{ ATOM } /n
216
+ FLAG_EXTENSION = /\\ #{ ATOM } /n
217
+ FLAG_KEYWORD = ATOM
218
+ FLAG_PERM = Regexp . union ( FLAG , "\\ *" )
219
+ MBX_FLAG = FLAG_EXTENSION
220
+
221
+ # flag-list = "(" [flag *(SP flag)] ")"
222
+ #
223
+ # part of resp-text-code:
224
+ # >>>
225
+ # "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")"
226
+ #
227
+ # parens from mailbox-list are included in the regexp:
228
+ # >>>
229
+ # mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
230
+ # *(SP mbx-list-oflag) /
231
+ # mbx-list-oflag *(SP mbx-list-oflag)
232
+ FLAG_LIST = /\G \( (#{ FLAG } (?:#{ SP } #{ FLAG } )*|)\) /ni
233
+ FLAG_PERM_LIST = /\G \( (#{ FLAG_PERM } (?:#{ SP } #{ FLAG_PERM } )*|)\) /ni
234
+ MBX_LIST_FLAGS = /\G \( (#{ MBX_FLAG } (?:#{ SP } #{ MBX_FLAG } )*|)\) /ni
235
+
188
236
# RFC3501:
189
237
# QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
190
238
# "\" quoted-specials
@@ -383,6 +431,14 @@ def label(word)
383
431
parse_error ( "unexpected atom %p, expected %p instead" , val , word )
384
432
end
385
433
434
+ # Use #label or #label_in to assert specific known labels
435
+ # (+tagged-ext-label+ only, not +atom+).
436
+ def label_in ( *labels )
437
+ lbl = tagged_ext_label and labels . include? ( lbl ) and return lbl
438
+ parse_error ( "unexpected atom %p, expected one of %s instead" ,
439
+ lbl , labels . join ( " or " ) )
440
+ end
441
+
386
442
# expects "OK" or "PREAUTH" and raises InvalidResponseError on failure
387
443
def resp_cond_auth__name
388
444
lbl = tagged_ext_label and AUTH_CONDS . include? lbl and return lbl
@@ -1084,18 +1140,21 @@ def header_fld_name
1084
1140
end
1085
1141
end
1086
1142
1143
+ # mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list /
1144
+ # "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
1145
+ # "STATUS" SP mailbox SP "(" [status-att-list] ")" /
1146
+ # number SP "EXISTS" / number SP "RECENT"
1147
+
1087
1148
def mailbox_data__flags
1088
- token = match ( T_ATOM )
1089
- name = token . value . upcase
1090
- match ( T_SPACE )
1091
- return UntaggedResponse . new ( name , flag_list , @str )
1149
+ name = label ( "FLAGS" )
1150
+ SP!
1151
+ UntaggedResponse . new ( name , flag_list , @str )
1092
1152
end
1093
1153
1094
1154
def mailbox_data__list
1095
- token = match ( T_ATOM )
1096
- name = token . value . upcase
1097
- match ( T_SPACE )
1098
- return UntaggedResponse . new ( name , mailbox_list , @str )
1155
+ name = label_in ( "LIST" , "LSUB" , "XLIST" )
1156
+ SP!
1157
+ UntaggedResponse . new ( name , mailbox_list , @str )
1099
1158
end
1100
1159
alias mailbox_data__lsub mailbox_data__list
1101
1160
alias mailbox_data__xlist mailbox_data__list
@@ -1645,28 +1704,38 @@ def address
1645
1704
return Address . new ( name , route , mailbox , host )
1646
1705
end
1647
1706
1648
- FLAG_REGEXP = /\
1649
- (?# FLAG )\\ ([^\x80 -\xff (){ \x00 -\x1f \x7f %"\\ ]+)|\
1650
- (?# ATOM )([^\x80 -\xff (){ \x00 -\x1f \x7f %*"\\ ]+)/n
1651
-
1707
+ # flag-list = "(" [flag *(SP flag)] ")"
1652
1708
def flag_list
1653
- if @str . index ( /\( ([^)]*)\) /ni , @pos )
1654
- @pos = $~. end ( 0 )
1655
- return $1. scan ( FLAG_REGEXP ) . collect { |flag , atom |
1656
- if atom
1657
- atom
1658
- else
1659
- flag . capitalize . intern
1660
- end
1661
- }
1662
- else
1663
- parse_error ( "invalid flag list" )
1664
- end
1709
+ match_re ( Patterns ::FLAG_LIST , "flag-list" ) [ 1 ]
1710
+ . split ( nil )
1711
+ . map! { _1 . start_with? ( "\\ " ) ? _1 [ 1 ..] . capitalize . to_sym : _1 }
1712
+ end
1713
+
1714
+ # "(" [flag-perm *(SP flag-perm)] ")"
1715
+ def flag_perm__list
1716
+ match_re ( Patterns ::FLAG_PERM_LIST , "PERMANENTFLAGS flag-perm list" ) [ 1 ]
1717
+ . split ( nil )
1718
+ . map! { _1 . start_with? ( "\\ " ) ? _1 [ 1 ..] . capitalize . to_sym : _1 }
1719
+ end
1720
+
1721
+ # Not checking for max one mbx-list-sflag in the parser.
1722
+ # >>>
1723
+ # mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
1724
+ # *(SP mbx-list-oflag) /
1725
+ # mbx-list-oflag *(SP mbx-list-oflag)
1726
+ # mbx-list-oflag = "\Noinferiors" / child-mbox-flag /
1727
+ # "\Subscribed" / "\Remote" / flag-extension
1728
+ # ; Other flags; multiple from this list are
1729
+ # ; possible per LIST response, but each flag
1730
+ # ; can only appear once per LIST response
1731
+ # mbx-list-sflag = "\NonExistent" / "\Noselect" / "\Marked" /
1732
+ # "\Unmarked"
1733
+ # ; Selectability flags; only one per LIST response
1734
+ def parens__mbx_list_flags
1735
+ match_re ( Patterns ::MBX_LIST_FLAGS , "mbx-list-flags" ) [ 1 ]
1736
+ . split ( nil ) . map! { _1 . capitalize . to_sym }
1665
1737
end
1666
1738
1667
- # TODO: not quite correct. flag-perm != flag
1668
- alias flag_perm__list flag_list
1669
-
1670
1739
# See https://www.rfc-editor.org/errata/rfc3501
1671
1740
#
1672
1741
# charset = atom / quoted
0 commit comments