@@ -283,6 +283,7 @@ def unescape_quoted(quoted)
283
283
Token = Struct . new ( :symbol , :value )
284
284
285
285
def_char_matchers :SP , " " , :T_SPACE
286
+ def_char_matchers :PLUS , "+" , :T_PLUS
286
287
287
288
def_char_matchers :lpar , "(" , :T_LPAR
288
289
def_char_matchers :rpar , ")" , :T_RPAR
@@ -325,6 +326,9 @@ def unescape_quoted(quoted)
325
326
# TODO: add to lexer and only match tagged-ext-label
326
327
def_token_matchers :tagged_ext_label , T_ATOM , T_NIL , send : :upcase
327
328
329
+ def_token_matchers :CRLF , T_CRLF
330
+ def_token_matchers :EOF , T_EOF
331
+
328
332
# atom = 1*ATOM-CHAR
329
333
# ATOM-CHAR = <any CHAR except atom-specials>
330
334
ATOM_TOKENS = [ T_ATOM , T_NUMBER , T_NIL , T_LBRA , T_PLUS ]
@@ -402,37 +406,40 @@ def case_insensitive__nstring
402
406
alias number64 number
403
407
alias number64? number?
404
408
409
+ # [RFC3501 & RFC9051:]
410
+ # response = *(continue-req / response-data) response-done
411
+ #
412
+ # For simplicity, response isn't interpreted as the combination of the
413
+ # three response types, but instead represents any individual server
414
+ # response. Our simplified interpretation is defined as:
415
+ # response = continue-req | response_data | response-tagged
416
+ #
417
+ # n.b: our "response-tagged" definition parses "greeting" too.
405
418
def response
406
- token = lookahead
407
- case token . symbol
408
- when T_PLUS
409
- result = continue_req
410
- when T_STAR
411
- result = response_untagged
412
- else
413
- result = response_tagged
414
- end
415
- while lookahead . symbol == T_SPACE
416
- # Ignore trailing space for Microsoft Exchange Server
417
- shift_token
418
- end
419
- match ( T_CRLF )
420
- match ( T_EOF )
421
- return result
419
+ resp = case lookahead! ( T_PLUS , T_STAR , *TAG_TOKENS ) . symbol
420
+ when T_PLUS then continue_req
421
+ when T_STAR then response_data
422
+ else response_tagged
423
+ end
424
+ accept_spaces # QUIRKY: Ignore trailing space (MS Exchange Server?)
425
+ CRLF!
426
+ EOF!
427
+ resp
422
428
end
423
429
430
+ # RFC3501 & RFC9051:
431
+ # continue-req = "+" SP (resp-text / base64) CRLF
432
+ #
433
+ # n.b: base64 is valid resp-text. And in the spirit of RFC9051 Appx E 23
434
+ # (and to workaround existing servers), we use the following grammar:
435
+ #
436
+ # continue-req = "+" (SP (resp-text)) CRLF
424
437
def continue_req
425
- match ( T_PLUS )
426
- token = lookahead
427
- if token . symbol == T_SPACE
428
- shift_token
429
- return ContinuationRequest . new ( resp_text , @str )
430
- else
431
- return ContinuationRequest . new ( ResponseText . new ( nil , "" ) , @str )
432
- end
438
+ PLUS!
439
+ ContinuationRequest . new ( SP? ? resp_text : ResponseText ::EMPTY , @str )
433
440
end
434
441
435
- def response_untagged
442
+ def response_data
436
443
match ( T_STAR )
437
444
match ( T_SPACE )
438
445
token = lookahead
@@ -1564,10 +1571,10 @@ def nil_atom
1564
1571
#
1565
1572
# This advances @pos directly so it's safe before changing @lex_state.
1566
1573
def accept_spaces
1567
- shift_token if @token &. symbol == T_SPACE
1568
- if @str . index ( SPACES_REGEXP , @pos )
1574
+ return false unless SP?
1575
+ @str . index ( SPACES_REGEXP , @pos ) and
1569
1576
@pos = $~. end ( 0 )
1570
- end
1577
+ true
1571
1578
end
1572
1579
1573
1580
def next_token
0 commit comments