123456789_123456789_123456789_123456789_123456789_

Class: Net::IMAP::ResponseParser

Relationships & Source Files
Namespace Children
Modules:
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: Object
Defined in: lib/net/imap/response_parser.rb,
lib/net/imap/response_parser/parser_utils.rb

Overview

Parses an IMAP server response.

Constant Summary

ResponseConditions - Included

AUTH_CONDS, BAD, BYE, GREETING_CONDS, NO, OK, PREAUTH, RESP_CONDS, RESP_COND_STATES, RESP_DATA_CONDS

Class Method Summary

ResponseParser::ParserUtils::Generator - Extended

def_char_matchers

we can skip lexer for single character matches, as a shortcut.

def_token_matchers

TODO: move coersion to the token.value method?

Instance Attribute Summary

Instance Method Summary

ParserUtils - Included

#accept

like match, but does not raise error on failure.

#accept_re,
#assert_no_lookahead

To be used conditionally:

#combine_adjacent

TODO: after checking the lookahead, use a regexp for remaining chars.

#lookahead,
#lookahead!

like match, without consuming the token.

#lookahead?

like accept, without consuming the token.

#match, #match_re, #parse_error, #peek_re, #peek_str?, #shift_token

Constructor Details

.newResponseParser

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 15

def initialize
  @str = nil
  @pos = nil
  @lex_state = nil
  @token = nil
end

Instance Attribute Details

#astring (readonly) Also known as: #mailbox

This method is for internal use only.

astring = 1*ASTRING-CHAR / string

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 503

def astring
  lookahead?(*ASTRING_CHARS_TOKENS) ? astring_chars : string
end

#astring?Boolean (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 507

def astring?
  lookahead?(*ASTRING_CHARS_TOKENS) ? astring_chars : string?
end

#atom (readonly) Also known as: #gt__number__lt, #section_part, #objectid

This method is for internal use only.

TODO: handle atom, astring_chars, and tag entirely inside the lexer

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 487

def atom;          combine_adjacent(*ATOM_TOKENS)          end

#atom?Boolean (readonly)

This method is for internal use only.

the #accept version of #atom

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 492

def atom?; -combine_adjacent(*ATOM_TOKENS) if lookahead?(*ATOM_TOKENS) end

#capability (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1637

alias capability  case_insensitive__atom

#capability? (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1638

alias capability? case_insensitive__atom?

#case_insensitive__atom (readonly) Also known as: #capability, #resp_text_code__name

This method is for internal use only.

Returns atom.upcase

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 495

def case_insensitive__atom; -combine_adjacent(*ATOM_TOKENS).upcase end

#case_insensitive__atom?Boolean (readonly) Also known as: #capability?

This method is for internal use only.

Returns atom?&.upcase

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 498

def case_insensitive__atom?
  -combine_adjacent(*ATOM_TOKENS).upcase if lookahead?(*ATOM_TOKENS)
end

#gt__number__lt (readonly)

This method is for internal use only.

Alias for #atom.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 943

alias gt__number__lt atom

#lookahead_thread_nested? (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1490

alias lookahead_thread_nested? lookahead_thread_list?

#mailbox (readonly)

This method is for internal use only.

Alias for #astring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 612

alias mailbox astring

#objectid (readonly)

This method is for internal use only.

Alias for #atom.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1987

alias objectid atom

#resp_text_code__name (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1838

alias resp_text_code__name case_insensitive__atom

#section_part (readonly)

This method is for internal use only.

Alias for #atom.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1310

alias section_part atom

#text (readonly)

This method is for internal use only.

TEXT-CHAR = <any CHAR except CR and LF> RFC3501:

text            = 1*TEXT-CHAR

RFC9051:

text            = 1*(TEXT-CHAR / UTF8-2 / UTF8-3 / UTF8-4)
                  ; Non-ASCII text can only be returned
                  ; after ENABLE IMAP4rev2 command
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1730

def text
  match_re(TEXT_REGEXP, "text")[0].force_encoding("UTF-8")
end

#text?Boolean (readonly)

This method is for internal use only.

an “accept” versiun of #text

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1735

def text?
  accept_re(TEXT_REGEXP)&.[](0)&.force_encoding("UTF-8")
end

Instance Method Details

#accept_spaces

This method is for internal use only.

The RFC is very strict about this and usually we should be too. But skipping spaces is usually a safe workaround for buggy servers.

This advances @pos directly so it’s safe before changing @lex_state.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 2023

def accept_spaces
  return false unless SP?
  @str.index(SPACES_REGEXP, @pos) and
    @pos = $~.end(0)
  true
end

#acl_data

This method is for internal use only.

acl-data = “ACL” SP mailbox *(SP identifier SP rights)

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1424

def acl_data
  token = match(T_ATOM)
  name = token.value.upcase
  match(T_SPACE)
  mailbox = astring
  data = []
  token = lookahead
  if token.symbol == T_SPACE
    shift_token
    while true
      token = lookahead
      case token.symbol
      when T_CRLF
        break
      when T_SPACE
        shift_token
      end
      user = astring
      match(T_SPACE)
      rights = astring
      data.push(MailboxACLItem.new(user, rights, mailbox))
    end
  end
  return UntaggedResponse.new(name, data, @str)
end

#addr_adl

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1907

alias addr_adl     nstring

#addr_host

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1908

alias addr_host    nstring

#addr_mailbox

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1909

alias addr_mailbox nstring

#addr_name

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1910

alias addr_name    nstring

#address

This method is for internal use only.

address = “(” addr-name SP addr-adl SP addr-mailbox SP

addr-host ")"

addr-adl = nstring addr-host = nstring addr-mailbox = nstring addr-name = nstring

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1892

def address
  if (match = accept_re(ADDRESS_REGEXP))
    # note that "NIL" isn't captured by the regexp
    name, route, mailbox, host = match.captures
      .map { Patterns.unescape_quoted _1 }
  else # address may include literals
    lpar; name    = addr_name
    SP!;  route   = addr_adl
    SP!;  mailbox = addr_mailbox
    SP!;  host    = addr_host
    rpar
  end
  Address.new(name, route, mailbox, host)
end

#astring_chars

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 488

def astring_chars; combine_adjacent(*ASTRING_CHARS_TOKENS) end

#body

This method is for internal use only.

RFC-3501 & RFC-9051:

body            = "(" (body-type-1part / body-type-mpart) ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1009

def body
  @lex_state = EXPR_DATA
  lpar; result = peek_lpar? ? body_type_mpart : body_type_1part; rpar
  result
ensure
  @lex_state = EXPR_BEG
end

#body_ext_1part

This method is for internal use only.

RFC2060

body_ext_1part  ::= body_fld_md5 [SPACE body_fld_dsp
                    [SPACE body_fld_lang
                    [SPACE 1#body_extension]]]
                    ;; MUST NOT be returned on non-extensible
                    ;; "BODY" fetch

RFC3501 & RFC9051

body-ext-1part  = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
                  [SP body-fld-loc *(SP body-extension)]]]
                    ; MUST NOT be returned on non-extensible
                    ; "BODY" fetch
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1180

def body_ext_1part
  fields = [];          fields << body_fld_md5
  SP? or return fields; fields << body_fld_dsp
  SP? or return fields; fields << body_fld_lang
  SP? or return fields; fields << body_fld_loc
  SP? or return fields; fields << body_extensions
  fields
end

#body_ext_mpart

This method is for internal use only.

RFC-2060:

body_ext_mpart  = body_fld_param [SP body_fld_dsp SP body_fld_lang
                  [SP 1#body_extension]]
                    ;; MUST NOT be returned on non-extensible
                    ;; "BODY" fetch

RFC-3501 & RFC-9051:

body-ext-mpart  = body-fld-param [SP body-fld-dsp [SP body-fld-lang
                  [SP body-fld-loc *(SP body-extension)]]]
                    ; MUST NOT be returned on non-extensible
                    ; "BODY" fetch
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1199

def body_ext_mpart
  fields = [];          fields << body_fld_param
  SP? or return fields; fields << body_fld_dsp
  SP? or return fields; fields << body_fld_lang
  SP? or return fields; fields << body_fld_loc
  SP? or return fields; fields << body_extensions
  fields
end

#body_extension

This method is for internal use only.

body-extension = nstring / number / number64 /

"(" body-extension *(SP body-extension) ")"
 ; Future expansion.  Client implementations
 ; MUST accept body-extension fields.  Server
 ; implementations MUST NOT generate
 ; body-extension fields except as defined by
 ; future Standard or Standards Track
 ; revisions of this specification.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1256

def body_extension
  if (uint = number64?) then uint
  elsif lpar?           then exts = body_extensions; rpar; exts
  else                       nstring
  end
end

#body_extensions

This method is for internal use only.

body-extension *(SP body-extension)

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1242

def body_extensions
  result = []
  result << body_extension; while SP? do result << body_extension end
  result
end

#body_fields

This method is for internal use only.

RFC-3501 & RFC-9051:

body-fields     = body-fld-param SP body-fld-id SP body-fld-desc SP
                  body-fld-enc SP body-fld-octets
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1145

def body_fields
  fields = []
  fields << body_fld_param; SP!
  fields << body_fld_id;    SP!
  fields << body_fld_desc;  SP!
  fields << body_fld_enc;   SP!
  fields << body_fld_octets
  fields
end

#body_fld_desc

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1208

alias body_fld_desc   nstring

#body_fld_dsp

This method is for internal use only.

body-fld-dsp = “(” string SP body-fld-param “)” / nil

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1221

def body_fld_dsp
  return if NIL?
  lpar; dsp_type = case_insensitive__string
  SP!;  param    = body_fld_param
  rpar
  ContentDisposition.new(dsp_type, param)
end

#body_fld_enc

This method is for internal use only.

RFC-3501 & RFC-9051:

body-fld-enc    = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
                  "QUOTED-PRINTABLE") DQUOTE) / string
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1218

alias body_fld_enc case_insensitive__string

#body_fld_id

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1209

alias body_fld_id     nstring

#body_fld_lang

This method is for internal use only.

body-fld-lang = nstring / “(” string *(SP string) “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1230

def body_fld_lang
  if lpar?
    result = [case_insensitive__string]
    result << case_insensitive__string while SP?
    rpar
    result
  else
    case_insensitive__nstring
  end
end

#body_fld_lines

This method is for internal use only.

Alias for #number64.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1211

alias body_fld_lines  number64 # number in 3501, number64 in 9051

#body_fld_loc

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1210

alias body_fld_loc    nstring

#body_fld_md5

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1212

alias body_fld_md5    nstring

#body_fld_octets

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1213

alias body_fld_octets number

#body_fld_param

This method is for internal use only.

RFC3501, RFC9051: body-fld-param = “(” string SP string *(SP string SP string) “)” / nil

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1157

def body_fld_param
  return if NIL?
  param = {}
  lpar
  name = case_insensitive__string; SP!; param[name] = string
  while SP?
    name = case_insensitive__string; SP!; param[name] = string
  end
  rpar
  param
end

#body_type_1part

This method is for internal use only.

RFC-3501 & RFC9051:

body-type-1part = (body-type-basic / body-type-msg / body-type-text)
                  [SP body-ext-1part]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1021

def body_type_1part
  # This regexp peek is a performance optimization.
  # The lookahead fallback would work fine too.
  m = peek_re(/\G(?:
      (?<TEXT>     "TEXT"    \s "[^"]+"             )
      |(?<MESSAGE> "MESSAGE" \s "(?:RFC822|GLOBAL)" )
      |(?<BASIC>   "[^"]+"   \s "[^"]+"             )
      |(?<MIXED>   "MIXED"                          )
     )/nix)
  choice = m&.named_captures&.compact&.keys&.first
  # In practice, the following line should never be used. But the ABNF
  # *does* allow literals, and this will handle them.
  choice ||= lookahead_case_insensitive__string!
  case choice
  when "BASIC"   then body_type_basic # => BodyTypeBasic
  when "MESSAGE" then body_type_msg   # => BodyTypeMessage | BodyTypeBasic
  when "TEXT"    then body_type_text  # => BodyTypeText
  when "MIXED"   then body_type_mixed # => BodyTypeMultipart (server bug)
  else                body_type_basic # might be a bug; server's or ours?
  end
end

#body_type_basic

This method is for internal use only.

RFC-3501 & RFC9051:

body-type-basic = media-basic SP body-fields
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1045

def body_type_basic
  type = media_basic # n.b. "basic" type isn't enforced here
  if lookahead_rpar? then return BodyTypeBasic.new(*type) end # invalid
  SP!;    flds = body_fields
  SP? and exts = body_ext_1part
  BodyTypeBasic.new(*type, *flds, *exts)
end

#body_type_mixed

This method is for internal use only.

This is a malformed body-type-mpart with no subparts.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1094

def body_type_mixed
  # warn "malformed body-type-mpart: multipart/mixed with no parts."
  type = media_subtype # => "MIXED"
  SP? and exts = body_ext_mpart
  BodyTypeMultipart.new("MULTIPART", type, nil, *exts)
end

#body_type_mpart

This method is for internal use only.

RFC-3501 & RFC-9051:

body-type-mpart = 1*body SP media-subtype
                  [SP body-ext-mpart]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1104

def body_type_mpart
  parts = [body]; parts << body until SP?; msubtype = media_subtype
  SP? and exts = body_ext_mpart
  BodyTypeMultipart.new("MULTIPART", msubtype, parts, *exts)
end

#body_type_msg

This method is for internal use only.

RFC-3501 & RFC-9051:

body-type-msg   = media-message SP body-fields SP envelope
                  SP body SP body-fld-lines
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1066

def body_type_msg
  # n.b. "message/rfc822" type isn't enforced here
  type = media_message
  SP!; flds = body_fields

  # Sometimes servers send body-type-basic when body-type-msg should be.
  # E.g: when a message/rfc822 part has "Content-Disposition: attachment".
  #
  # * SP "("     --> SP envelope       --> continue as body-type-msg
  # * ")"        --> no body-ext-1part --> completed body-type-basic
  # * SP nstring --> SP body-fld-md5
  #              --> SP body-ext-1part --> continue as body-type-basic
  #
  # It's probably better to return BodyTypeBasic---even for
  # "message/rfc822"---than BodyTypeMessage with invalid fields.
  unless peek_str?(" (")
    SP? and exts = body_ext_1part
    return BodyTypeBasic.new(*type, *flds, *exts)
  end

  SP!; env   = envelope
  SP!; bdy   = body
  SP!; lines = body_fld_lines
  SP? and exts = body_ext_1part
  BodyTypeMessage.new(*type, *flds, env, bdy, lines, *exts)
end

#body_type_text

This method is for internal use only.

RFC-3501 & RFC-9051:

body-type-text  = media-text SP body-fields SP body-fld-lines
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1055

def body_type_text
  type = media_text
  SP!;   flds  = body_fields
  SP!;   lines = body_fld_lines
  SP? and exts = body_ext_1part
  BodyTypeText.new(*type, *flds, lines, *exts)
end

#capability__list Also known as: #resp_code__capability

This method is for internal use only.

As a workaround for buggy servers, allow a trailing SP:

*(SP capability) [SP]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1627

def capability__list
  list = []; while SP? && (capa = capability?) do list << capa end; list
end

#capability_data__untagged

This method is for internal use only.

The presence of “IMAP4rev1” or “IMAP4rev2” is unenforced here. The grammar rule is used by both response-data and resp-text-code. But this method only returns UntaggedResponse (response-data).

RFC3501:

capability-data  = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
                   *(SP capability)

RFC9051:

capability-data  = "CAPABILITY" *(SP capability) SP "IMAP4rev2"
                   *(SP capability)
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1616

def capability_data__untagged
  UntaggedResponse.new label("CAPABILITY"), capability__list, @str
end

#case_insensitive__nstring

This method is for internal use only.

use where nstring represents “LABEL” values

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 556

def case_insensitive__nstring
  NIL? ? nil : case_insensitive__string
end

#charset

This method is for internal use only.

See www.rfc-editor.org/errata/rfc3501

charset = atom / quoted

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1963

def charset; quoted? || atom end

#charset__list

This method is for internal use only.

“(” charset *(SP charset) “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1846

def charset__list
  lpar; list = [charset]; while SP? do list << charset end; rpar; list
end

#comparator_data(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 776

alias comparator_data         response_data__unhandled

#continue_req

This method is for internal use only.

RFC3501 & RFC9051:

continue-req    = "+" SP (resp-text / base64) CRLF

n.b: base64 is valid resp-text. And in the spirit of RFC9051 Appx E 23 (and to workaround existing servers), we use the following grammar:

continue-req    = "+" (SP (resp-text)) CRLF
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 673

def continue_req
  PLUS!
  ContinuationRequest.new(SP? ? resp_text : ResponseText::EMPTY, @str)
end

#date_time

This method is for internal use only.

date-time = DQUOTE date-day-fixed “-” date-month “-” date-year

SP time SP zone DQUOTE
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1004

alias date_time quoted

#enable_data

This method is for internal use only.

enable-data = “ENABLED” *(SP capability)

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1621

def enable_data
  UntaggedResponse.new label("ENABLED"), capability__list, @str
end

#env_bcc

This method is for internal use only.

Alias for #nlist__address.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 994

alias env_bcc      nlist__address

#env_cc

This method is for internal use only.

Alias for #nlist__address.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 993

alias env_cc       nlist__address

#env_date

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 972

alias env_date        nstring

#env_from

This method is for internal use only.

Alias for #nlist__address.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 989

alias env_from     nlist__address

#env_in_reply_to

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 974

alias env_in_reply_to nstring

#env_message_id

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 975

alias env_message_id  nstring

#env_reply_to

This method is for internal use only.

Alias for #nlist__address.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 991

alias env_reply_to nlist__address

#env_sender

This method is for internal use only.

Alias for #nlist__address.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 990

alias env_sender   nlist__address

#env_subject

This method is for internal use only.

Alias for #nstring.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 973

alias env_subject     nstring

#env_to

This method is for internal use only.

Alias for #nlist__address.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 992

alias env_to       nlist__address

#envelope

This method is for internal use only.

RFC3501 & RFC9051:

envelope        = "(" env-date SP env-subject SP env-from SP
                  env-sender SP env-reply-to SP env-to SP env-cc SP
                  env-bcc SP env-in-reply-to SP env-message-id ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 949

def envelope
  @lex_state = EXPR_DATA
  lpar; date        = env_date
  SP!;  subject     = env_subject
  SP!;  from        = env_from
  SP!;  sender      = env_sender
  SP!;  reply_to    = env_reply_to
  SP!;  to          = env_to
  SP!;  cc          = env_cc
  SP!;  bcc         = env_bcc
  SP!;  in_reply_to = env_in_reply_to
  SP!;  message_id  = env_message_id
  rpar
  Envelope.new(date, subject, from, sender, reply_to,
               to, cc, bcc, in_reply_to, message_id)
ensure
  @lex_state = EXPR_BEG
end

#esearch_response(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 769

alias esearch_response        response_data__unhandled

#expunged_resp(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 770

alias expunged_resp           response_data__unhandled

#flag_list

This method is for internal use only.

flag-list = “(” [flag *(SP flag)] “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1913

def flag_list
  if (match = accept_re(Patterns::FLAG_LIST))
    match[1].split(nil)
      .map! { _1.delete_prefix!("\\") ? _1.capitalize.to_sym : _1 }
  else
    quirky__flag_list "flags-list"
  end
end

#flag_perm__list

This method is for internal use only.

“(” [flag-perm *(SP flag-perm)] “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1923

def flag_perm__list
  if (match = accept_re(Patterns::FLAG_PERM_LIST))
    match[1].split(nil)
      .map! { _1.delete_prefix!("\\") ? _1.capitalize.to_sym : _1 }
  else
    quirky__flag_list "PERMANENTFLAGS flag-perm list"
  end
end

#header_fld_name

This method is for internal use only.

RFC3501 & RFC9051:

header-fld-name = astring

NOTE: Previously, ::Net::IMAP recreated the raw original source string. Now, it grabs the raw encoded value using @str and @pos. A future version may simply return the decoded astring value. Although that is technically incompatible, it should almost never make a difference: all standard header field names are valid atoms:

www.iana.org/assignments/message-headers/message-headers.xhtml

Although RFC3501 allows any astring, RFC5322-valid header names are one or more of the printable US-ASCII characters, except SP and colon. So empty string isn’t valid, and literals aren’t needed and should not be used. This is explicitly unchanged by [I18N-HDRS] (RFC6532).

RFC5233:

optional-field  =   field-name ":" unstructured CRLF
field-name      =   1*ftext
ftext           =   %d33-57 /          ; Printable US-ASCII
                    %d59-126           ;  characters not including
                                       ;  ":".
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1334

def header_fld_name
  assert_no_lookahead
  start = @pos
  astring
  @str[start...@pos - 1]
end

#header_list

This method is for internal use only.

header-list = “(” header-fld-name *(SP header-fld-name) “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1300

def header_list
  str = +""
  str << lpar << header_fld_name
  str << " "  << header_fld_name while SP?
  str << rpar
end

#id_response

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1640

def id_response
  token = match(T_ATOM)
  name = token.value.upcase
  match(T_SPACE)
  token = match(T_LPAR, T_NIL)
  if token.symbol == T_NIL
    return UntaggedResponse.new(name, nil, @str)
  else
    data = {}
    while true
      token = lookahead
      case token.symbol
      when T_RPAR
        shift_token
        break
      when T_SPACE
        shift_token
        next
      else
        key = string
        match(T_SPACE)
        val = nstring
        data[key] = val
      end
    end
    return UntaggedResponse.new(name, data, @str)
  end
end

#label(word)

This method is for internal use only.

Use #label or #label_in to assert specific known labels (tagged-ext-label only, not #atom).

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 513

def label(word)
  (val = tagged_ext_label) == word and return val
  parse_error("unexpected atom %p, expected %p instead", val, word)
end

#label_in(*labels)

This method is for internal use only.

Use #label or #label_in to assert specific known labels (tagged-ext-label only, not #atom).

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 520

def label_in(*labels)
  lbl = tagged_ext_label and labels.include?(lbl) and return lbl
  parse_error("unexpected atom %p, expected one of %s instead",
              lbl, labels.join(" or "))
end

#language_data(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 775

alias language_data           response_data__unhandled

#listrights_data(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 772

alias listrights_data         response_data__unhandled

#lookahead_body?

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1016

alias lookahead_body? lookahead_lpar?

#lookahead_thread_list? Also known as: #lookahead_thread_nested?

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1489

alias lookahead_thread_list?   lookahead_lpar?

#mailbox_data__exists

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 839

alias mailbox_data__exists  response_data__simple_numeric

#mailbox_data__flags

This method is for internal use only.

mailbox-data = “FLAGS” SP flag-list / “LIST” SP mailbox-list /

"LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
"STATUS" SP mailbox SP "(" [status-att-list] ")" /
number SP "EXISTS" / number SP "RECENT"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1346

def mailbox_data__flags
  name = label("FLAGS")
  SP!
  UntaggedResponse.new(name, flag_list, @str)
end

#mailbox_data__list Also known as: #mailbox_data__lsub, #mailbox_data__xlist

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1352

def mailbox_data__list
  name = label_in("LIST", "LSUB", "XLIST")
  SP!
  UntaggedResponse.new(name, mailbox_list, @str)
end

#mailbox_data__lsub

This method is for internal use only.

Alias for #mailbox_data__list.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1357

alias mailbox_data__lsub  mailbox_data__list

#mailbox_data__recent

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 840

alias mailbox_data__recent  response_data__simple_numeric

#mailbox_data__search Also known as: #sort_data

This method is for internal use only.

RFC3501:

mailbox-data        = "SEARCH" *(SP nz-number) / ...

RFC5256: SORT

sort-data           = "SORT" *(SP nz-number)

RFC7162: CONDSTORE, QRESYNC

mailbox-data        =/ "SEARCH" [1*(SP nz-number) SP
                       search-sort-mod-seq]
sort-data           = "SORT" [1*(SP nz-number) SP
                        search-sort-mod-seq]
                        ; Updates the SORT response from RFC 5256.
search-sort-mod-seq = "(" "MODSEQ" SP mod-sequence-value ")"

RFC9051:

mailbox-data        = obsolete-search-response / ...
obsolete-search-response = "SEARCH" *(SP nz-number)
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1464

def mailbox_data__search
  name = label_in("SEARCH", "SORT")
  data = []
  while _ = SP? && nz_number? do data << _ end
  if lpar?
    label("MODSEQ"); SP!
    modseq = mod_sequence_value
    rpar
  end
  data = SearchResult.new(data, modseq: modseq)
  UntaggedResponse.new(name, data, @str)
end

#mailbox_data__status

This method is for internal use only.

mailbox-data =/ “STATUS” SP mailbox SP “(” [status-att-list] “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1530

def mailbox_data__status
  resp_name  = label("STATUS"); SP!
  mbox_name  = mailbox;         SP!
  lpar; attr = status_att_list; rpar
  UntaggedResponse.new(resp_name, StatusData.new(mbox_name, attr), @str)
end

#mailbox_data__xlist

This method is for internal use only.

Alias for #mailbox_data__list.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1358

alias mailbox_data__xlist mailbox_data__list

#mailbox_list

This method is for internal use only.

mailbox-list = “(” [mbx-list-flags] “)” SP

       (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
       [SP mbox-list-extended]
; This is the list information pointed to by the ABNF
; item "mailbox-data", which is defined above
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1365

def mailbox_list
  lpar; attr  = peek_rpar? ? [] : mbx_list_flags; rpar
  SP!;  delim = nquoted
  SP!;  name  = mailbox
  # TODO: mbox-list-extended
  MailboxList.new(attr, delim, name)
end

#mbx_list_flags

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1941

def mbx_list_flags
  match_re(Patterns::MBX_LIST_FLAGS, "mbx-list-flags")[1]
    .split(nil)
    .map! { _1.delete_prefix!("\\"); _1.capitalize.to_sym }
end

#media_basic

This method is for internal use only.

Alias for #media_type.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1136

alias media_basic   media_type # */* --- catchall

#media_message

This method is for internal use only.

Alias for #media_type.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1137

alias media_message media_type # message/rfc822, message/global

#media_subtype

This method is for internal use only.

text/*

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1140

alias media_subtype case_insensitive__string

#media_text

This method is for internal use only.

Alias for #media_type.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1138

alias media_text    media_type # text/*

#media_type Also known as: #media_basic, #media_message, #media_text

This method is for internal use only.

n.b. this handles both type and subtype

RFC-3501 vs RFC-9051:

media-basic     = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
                  "MESSAGE" /
                  "VIDEO") DQUOTE) / string) SP media-subtype
media-basic     = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
                  "FONT" / "MESSAGE" / "MODEL" /
                  "VIDEO") DQUOTE) / string) SP media-subtype

media-message   = DQUOTE "MESSAGE" DQUOTE SP
                  DQUOTE "RFC822" DQUOTE
media-message   = DQUOTE "MESSAGE" DQUOTE SP
                  DQUOTE ("RFC822" / "GLOBAL") DQUOTE

RFC-3501 & RFC-9051:

media-text      = DQUOTE "TEXT" DQUOTE SP media-subtype
media-subtype   = string
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1128

def media_type
  mtype = case_insensitive__string
  SP? or return mtype, nil # ??? quirky!
  msubtype = media_subtype
  return mtype, msubtype
end

#message_data__converted(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 777

alias message_data__converted response_data__unhandled

#message_data__expunge

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 838

alias message_data__expunge response_data__simple_numeric

#message_data__fetch

This method is for internal use only.

message-data = nz-number SP (“EXPUNGE” / (“FETCH” SP msg-att))

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 825

def message_data__fetch
  seq  = nz_number;     SP!
  name = label "FETCH"; SP!
  data = FetchData.new(seq, msg_att(seq))
  UntaggedResponse.new(name, data, @str)
end

#metadata_resp(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 774

alias            response_data__unhandled

#mod_sequence_value Also known as: #permsg_modsequence

This method is for internal use only.

Alias for #nz_number64.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1970

alias mod_sequence_value nz_number64

#mod_sequence_valzer

This method is for internal use only.

Alias for #number64.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1979

alias mod_sequence_valzer number64

#msg_att(n)

This method is for internal use only.

RFC3501 & RFC9051:

msg-att         = "(" (msg-att-dynamic / msg-att-static)
                   *(SP (msg-att-dynamic / msg-att-static)) ")"

msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"

RFC5257 (ANNOTATE extension):

msg-att-dynamic =/ "ANNOTATION" SP
                     ( "(" entry-att *(SP entry-att) ")" /
                       "(" entry *(SP entry) ")" )

RFC7162 (CONDSTORE extension):

msg-att-dynamic =/ fetch-mod-resp
fetch-mod-resp  = "MODSEQ" SP "(" permsg-modsequence ")"

RFC8970 (PREVIEW extension):

msg-att-dynamic =/ "PREVIEW" SP nstring

RFC3501:

msg-att-static  = "ENVELOPE" SP envelope /
                  "INTERNALDATE" SP date-time /
                  "RFC822" [".HEADER" / ".TEXT"] SP nstring /
                  "RFC822.SIZE" SP number /
                  "BODY" ["STRUCTURE"] SP body /
                  "BODY" section ["<" number ">"] SP nstring /
                  "UID" SP uniqueid

RFC3516 (BINARY extension):

msg-att-static  =/ "BINARY" section-binary SP (nstring / literal8)
                 / "BINARY.SIZE" section-binary SP number

RFC8514 (SAVEDATE extension):

msg-att-static  =/ "SAVEDATE" SP (date-time / nil)

RFC8474 (OBJECTID extension):

msg-att-static =/ fetch-emailid-resp / fetch-threadid-resp
fetch-emailid-resp  = "EMAILID" SP "(" objectid ")"
fetch-threadid-resp = "THREADID" SP ( "(" objectid ")" / nil )

RFC9051:

msg-att-static  = "ENVELOPE" SP envelope /
                  "INTERNALDATE" SP date-time /
                  "RFC822.SIZE" SP number64 /
                  "BODY" ["STRUCTURE"] SP body /
                  "BODY" section ["<" number ">"] SP nstring /
                  "BINARY" section-binary SP (nstring / literal8) /
                  "BINARY.SIZE" section-binary SP number /
                  "UID" SP uniqueid

Re www.rfc-editor.org/errata/eid7246, I’m adding “offset” to the official “BINARY” ABNF, like so:

msg-att-static   =/ "BINARY" section-binary ["<" number ">"] SP
                    (nstring / literal8)
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 889

def msg_att(n)
  lpar
  attr = {}
  while true
    name = msg_att__label; SP!
    val =
      case name
      when "UID"                  then uniqueid
      when "FLAGS"                then flag_list
      when "BODY"                 then body
      when /\ABODY\[/ni           then nstring
      when "BODYSTRUCTURE"        then body
      when "ENVELOPE"             then envelope
      when "INTERNALDATE"         then date_time
      when "RFC822.SIZE"          then number64
      when /\ABINARY\[/ni         then nstring8           # BINARY, IMAP4rev2
      when /\ABINARY\.SIZE\[/ni   then number             # BINARY, IMAP4rev2
      when "RFC822"               then nstring            # not in rev2
      when "RFC822.HEADER"        then nstring            # not in rev2
      when "RFC822.TEXT"          then nstring            # not in rev2
      when "MODSEQ"               then parens__modseq     # CONDSTORE
      when "EMAILID"              then parens__objectid   # OBJECTID
      when "THREADID"             then nparens__objectid  # OBJECTID
      when "X-GM-MSGID"           then x_gm_id            # GMail
      when "X-GM-THRID"           then x_gm_id            # GMail
      when "X-GM-LABELS"          then x_gm_labels        # GMail
      else parse_error("unknown attribute `%s' for {%d}", name, n)
      end
    attr[name] = val
    break unless SP?
    break if lookahead_rpar?
  end
  rpar
  attr
end

#msg_att__label

This method is for internal use only.

appends “[section]” and “<partial>” to the base label

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 926

def msg_att__label
  case (name = tagged_ext_label)
  when /\A(?:RFC822(?:\.HEADER|\.TEXT)?)\z/ni
    # ignoring "[]" fixes https://bugs.ruby-lang.org/issues/5620
    lbra? and rbra
  when "BODY"
    peek_lbra? and name << section and
      peek_str?("<") and name << gt__number__lt # partial
  when "BINARY", "BINARY.SIZE"
    name << section_binary
    # see https://www.rfc-editor.org/errata/eid7246 and the note above
    peek_str?("<") and name << gt__number__lt # partial
  end
  name
end

#myrights_data(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 773

alias myrights_data           response_data__unhandled

#namespace

This method is for internal use only.

namespace = nil / “(” 1*namespace-descr “)”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1687

def namespace
  NIL? and return []
  lpar
  list = [namespace_descr]
  list << namespace_descr until rpar?
  list
end

#namespace_descr

This method is for internal use only.

namespace-descr = “(” string SP

(DQUOTE QUOTED-CHAR DQUOTE / nil)
 [namespace-response-extensions] ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1698

def namespace_descr
  lpar
  prefix     = string; SP!
  delimiter  = nquoted # n.b: should only accept single char
  extensions = namespace_response_extensions
  rpar
  Namespace.new(prefix, delimiter, extensions)
end

#namespace_response

This method is for internal use only.

namespace-response = “NAMESPACE” SP namespace

     SP namespace SP namespace
; The first Namespace is the Personal Namespace(s).
; The second Namespace is the Other Users'
; Namespace(s).
; The third Namespace is the Shared Namespace(s).
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1675

def namespace_response
  name = label("NAMESPACE")
  @lex_state = EXPR_DATA
  data = Namespaces.new((SP!; namespace),
                        (SP!; namespace),
                        (SP!; namespace))
  UntaggedResponse.new(name, data, @str)
ensure
  @lex_state = EXPR_BEG
end

#namespace_response_extensions

This method is for internal use only.

namespace-response-extensions = *namespace-response-extension namespace-response-extension = SP string SP

"(" string *(SP string) ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1710

def namespace_response_extensions
  data = {}
  while SP?
    name = string; SP!
    lpar
    data[name] ||= []
    data[name] << string
    data[name] << string while SP?
    rpar
  end
  data
end

#ndatetime

This method is for internal use only.

Alias for #nquoted.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1005

alias ndatetime nquoted

#next_token

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 2030

def next_token
  case @lex_state
  when EXPR_BEG
    if @str.index(BEG_REGEXP, @pos)
      @pos = $~.end(0)
      if $1
        return Token.new(T_SPACE, $+)
      elsif $2
        len = $+.to_i
        val = @str[@pos, len]
        @pos += len
        return Token.new(T_LITERAL8, val)
      elsif $3 && $7
        # greedily match ATOM, prefixed with NUMBER, NIL, or PLUS.
        return Token.new(T_ATOM, $3)
      elsif $4
        return Token.new(T_NIL, $+)
      elsif $5
        return Token.new(T_NUMBER, $+)
      elsif $6
        return Token.new(T_PLUS, $+)
      elsif $8
        # match ATOM, without a NUMBER, NIL, or PLUS prefix
        return Token.new(T_ATOM, $+)
      elsif $9
        return Token.new(T_QUOTED, Patterns.unescape_quoted($+))
      elsif $10
        return Token.new(T_LPAR, $+)
      elsif $11
        return Token.new(T_RPAR, $+)
      elsif $12
        return Token.new(T_BSLASH, $+)
      elsif $13
        return Token.new(T_STAR, $+)
      elsif $14
        return Token.new(T_LBRA, $+)
      elsif $15
        return Token.new(T_RBRA, $+)
      elsif $16
        len = $+.to_i
        val = @str[@pos, len]
        @pos += len
        return Token.new(T_LITERAL, val)
      elsif $17
        return Token.new(T_PERCENT, $+)
      elsif $18
        return Token.new(T_CRLF, $+)
      elsif $19
        return Token.new(T_EOF, $+)
      else
        parse_error("[Net::IMAP BUG] BEG_REGEXP is invalid")
      end
    else
      @str.index(/\S*/n, @pos)
      parse_error("unknown token - %s", $&.dump)
    end
  when EXPR_DATA
    if @str.index(DATA_REGEXP, @pos)
      @pos = $~.end(0)
      if $1
        return Token.new(T_SPACE, $+)
      elsif $2
        return Token.new(T_NIL, $+)
      elsif $3
        return Token.new(T_NUMBER, $+)
      elsif $4
        return Token.new(T_QUOTED, Patterns.unescape_quoted($+))
      elsif $5
        len = $+.to_i
        val = @str[@pos, len]
        @pos += len
        return Token.new(T_LITERAL, val)
      elsif $6
        return Token.new(T_LPAR, $+)
      elsif $7
        return Token.new(T_RPAR, $+)
      else
        parse_error("[Net::IMAP BUG] DATA_REGEXP is invalid")
      end
    else
      @str.index(/\S*/n, @pos)
      parse_error("unknown token - %s", $&.dump)
    end
  else
    parse_error("invalid @lex_state - %s", @lex_state.inspect)
  end
end

#nil_atom

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 2012

def nil_atom
  match(T_NIL)
  return nil
end

#nlist__address Also known as: #env_from, #env_sender, #env_reply_to, #env_to, #env_cc, #env_bcc

This method is for internal use only.

env-from = “(” 1*address “)” / nil env-sender = “(” 1*address “)” / nil env-reply-to = “(” 1*address “)” / nil env-to = “(” 1*address “)” / nil env-cc = “(” 1*address “)” / nil env-bcc = “(” 1*address “)” / nil

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 983

def nlist__address
  return if NIL?
  lpar; list = [address]; list << address until (quirky_SP?; rpar?)
  list
end

#nparens__objectid

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1990

def nparens__objectid; NIL? ? nil : parens__objectid end

#nquoted Also known as: #ndatetime

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 551

def nquoted
  NIL? ? nil : quoted
end

#nstring Also known as: #env_date, #env_subject, #env_in_reply_to, #env_message_id, #body_fld_desc, #body_fld_id, #body_fld_loc, #body_fld_md5, #addr_adl, #addr_host, #addr_mailbox, #addr_name

This method is for internal use only.

nstring = string / nil

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 543

def nstring
  NIL? ? nil : string
end

#nstring8

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 547

def nstring8
  NIL? ? nil : string8
end

#number64 Also known as: #body_fld_lines, #mod_sequence_valzer

This method is for internal use only.

valid number ranges are not enforced by parser

number64        = 1*DIGIT
                    ; Unsigned 63-bit integer
                    ; (0 <= n <= 9,223,372,036,854,775,807)
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 618

alias number64    number

#number64?

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 619

alias number64?   number?

#nz_number Also known as: #nz_number64, #uniqueid

This method is for internal use only.

valid number ranges are not enforced by parser

nz-number       = digit-nz *DIGIT
                    ; Non-zero unsigned 32-bit integer
                    ; (0 < n < 4,294,967,296)
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 625

alias nz_number   number

#nz_number64 Also known as: #mod_sequence_value

This method is for internal use only.

Alias for #nz_number.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 632

alias nz_number64 nz_number

#nz_number?

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 626

alias nz_number?  number?

#parens__modseq

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1981

def parens__modseq; lpar; _ = permsg_modsequence; rpar; _ end

#parens__objectid

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1989

def parens__objectid; lpar; _ = objectid; rpar; _ end

#parse(str) ⇒ ContinuationRequest #parse(str) ⇒ UntaggedResponse #parse(str) ⇒ TaggedResponse

Raises ResponseParseError for unparsable strings.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 28

def parse(str)
  @str = str
  @pos = 0
  @lex_state = EXPR_BEG
  @token = nil
  return response
end

#permsg_modsequence

This method is for internal use only.

Alias for #mod_sequence_value.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1975

alias permsg_modsequence mod_sequence_value

#quirky__flag_list(name)

This method is for internal use only.

This allows illegal “]” in flag names (Gmail), or “*” in a FLAGS response (greenmail).

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1934

def quirky__flag_list(name)
  match_re(Patterns::QUIRKY_FLAGS_LIST, "quirks mode #{name}")[1]
    .scan(Patterns::QUIRKY_FLAG)
    .map! { _1.delete_prefix!("\\") ? _1.capitalize.to_sym : _1 }
end

#quirky_SP?

This method is for internal use only.

Used when servers erroneously send an extra SP.

As of 2023-11-28, Outlook.com (still) sends SP

between address in <tt>env-*</tt> lists.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1000

alias quirky_SP? SP?

#quota_response

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1373

def quota_response
  # If quota never established, get back
  # `NO Quota root does not exist'.
  # If quota removed, get `()' after the
  # folder spec with no mention of `STORAGE'.
  token = match(T_ATOM)
  name = token.value.upcase
  match(T_SPACE)
  mailbox = astring
  match(T_SPACE)
  match(T_LPAR)
  token = lookahead
  case token.symbol
  when T_RPAR
    shift_token
    data = MailboxQuota.new(mailbox, nil, nil)
    return UntaggedResponse.new(name, data, @str)
  when T_ATOM
    shift_token
    match(T_SPACE)
    token = match(T_NUMBER)
    usage = token.value
    match(T_SPACE)
    token = match(T_NUMBER)
    quota = token.value
    match(T_RPAR)
    data = MailboxQuota.new(mailbox, usage, quota)
    return UntaggedResponse.new(name, data, @str)
  else
    parse_error("unexpected token %s", token.symbol)
  end
end

#quotaroot_response

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1406

def quotaroot_response
  # Similar to getquota, but only admin can use getquota.
  token = match(T_ATOM)
  name = token.value.upcase
  match(T_SPACE)
  mailbox = astring
  quotaroots = []
  while true
    token = lookahead
    break unless token.symbol == T_SPACE
    shift_token
    quotaroots.push(astring)
  end
  data = MailboxQuotaRoot.new(mailbox, quotaroots)
  return UntaggedResponse.new(name, data, @str)
end

#remaining_unparsed

This method is for internal use only.

reads all the way up until CRLF

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 761

def remaining_unparsed
  str = @str[@pos...-2] and @pos += str.bytesize
  str&.empty? ? nil : str
end

#resp_code__capability

This method is for internal use only.

Alias for #capability__list.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1631

alias resp_code__capability capability__list

#resp_code_apnd__data

This method is for internal use only.

already matched: “APPENDUID”

UIDPLUS ABNF

www.rfc-editor.org/rfc/rfc4315.html#section-4

resp-code-apnd  = "APPENDUID" SP nz-number SP append-uid
append-uid      = uniqueid
append-uid      =/ uid-set
                  ; only permitted if client uses [MULTIAPPEND]
                  ; to append multiple messages.

n.b, uniqueid ⊂ uid-set. To avoid inconsistent return types, we always match uid_set even if that returns a single-member array.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1862

def resp_code_apnd__data
  validity = number; SP!
  dst_uids = uid_set # uniqueid ⊂ uid-set
  UIDPlusData.new(validity, nil, dst_uids)
end

#resp_code_copy__data

This method is for internal use only.

already matched: “COPYUID”

resp-code-copy = “COPYUID” SP nz-number SP uid-set SP uid-set

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1871

def resp_code_copy__data
  validity = number;  SP!
  src_uids = uid_set; SP!
  dst_uids = uid_set
  UIDPlusData.new(validity, src_uids, dst_uids)
end

#resp_cond_auth

This method is for internal use only.

resp-cond-auth = (“OK” / “PREAUTH”) SP resp-text

NOTE: In the spirit of RFC9051 Appx E 23 (and to workaround existing servers), we don’t require a final SP and instead parse this as:

resp-cond-auth   = ("OK" / "PREAUTH") [SP resp-text]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 806

def resp_cond_auth
  UntaggedResponse.new(resp_cond_auth__name,
                       SP? ? resp_text : ResponseText::EMPTY,
                       @str)
end

#resp_cond_auth__name

This method is for internal use only.

expects “OK” or “PREAUTH” and raises InvalidResponseError on failure

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 527

def resp_cond_auth__name
  lbl = tagged_ext_label and AUTH_CONDS.include? lbl and return lbl
  raise InvalidResponseError, "bad response type %p, expected %s" % [
    lbl, AUTH_CONDS.join(" or ")
  ]
end

#resp_cond_bye

This method is for internal use only.

resp-cond-bye = “BYE” SP resp-text

NOTE: In the spirit of RFC9051 Appx E 23 (and to workaround existing servers), we don’t require a final SP and instead parse this as:

resp-cond-bye    = "BYE" [SP resp-text]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 818

def resp_cond_bye
  UntaggedResponse.new(label(BYE),
                       SP? ? resp_text : ResponseText::EMPTY,
                       @str)
end

#resp_cond_state

This method is for internal use only.

RFC3501 & RFC9051:

resp-cond-state  = ("OK" / "NO" / "BAD") SP resp-text

NOTE: In the spirit of RFC9051 Appx E 23 (and to workaround existing servers), we don’t require a final SP and instead parse this as:

resp-cond-state = ("OK" / "NO" / "BAD") [SP resp-text]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 792

def resp_cond_state
  [resp_cond_state__name, SP? ? resp_text : ResponseText::EMPTY]
end

#resp_cond_state__name

This method is for internal use only.

expects “OK” or “NO” or “BAD” and raises InvalidResponseError on failure

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 535

def resp_cond_state__name
  lbl = tagged_ext_label and RESP_COND_STATES.include? lbl and return lbl
  raise InvalidResponseError, "bad response type %p, expected %s" % [
    lbl, RESP_COND_STATES.join(" or ")
  ]
end

#resp_cond_state__untagged

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 796

def resp_cond_state__untagged
  UntaggedResponse.new(*resp_cond_state, @str)
end

#resp_text

This method is for internal use only.

RFC3501:

resp-text       = ["[" resp-text-code "]" SP] text

RFC9051:

resp-text       = ["[" resp-text-code "]" SP] [text]

We leniently re-interpret this as

resp-text       = ["[" resp-text-code "]" [SP [text]] / [text]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1746

def resp_text
  if lbra?
    code = resp_text_code; rbra
    ResponseText.new(code, SP? && text? || "")
  else
    ResponseText.new(nil, text? || "")
  end
end

#resp_text_code

This method is for internal use only.

RFC3501 (See www.rfc-editor.org/errata/rfc3501):

resp-text-code   = "ALERT" /
                   "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
                   capability-data / "PARSE" /
                   "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" /
                   "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
                   "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
                   "UNSEEN" SP nz-number /
                   atom [SP 1*<any TEXT-CHAR except "]">]
capability-data  = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
                   *(SP capability)

RFC5530:

resp-text-code  =/ "UNAVAILABLE" / "AUTHENTICATIONFAILED" /
                  "AUTHORIZATIONFAILED" / "EXPIRED" /
                  "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" /
                  "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" /
                  "SERVERBUG" / "CLIENTBUG" / "CANNOT" /
                  "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" /
                  "NONEXISTENT"

RFC9051:

resp-text-code   = "ALERT" /
                   "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
                   capability-data / "PARSE" /
                   "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" /
                   "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
                   "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
                   resp-code-apnd / resp-code-copy / "UIDNOTSTICKY" /
                   "UNAVAILABLE" / "AUTHENTICATIONFAILED" /
                   "AUTHORIZATIONFAILED" / "EXPIRED" /
                   "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" /
                   "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" /
                   "SERVERBUG" / "CLIENTBUG" / "CANNOT" /
                   "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" /
                   "NONEXISTENT" / "NOTSAVED" / "HASCHILDREN" /
                   "CLOSED" /
                   "UNKNOWN-CTE" /
                   atom [SP 1*<any TEXT-CHAR except "]">]
capability-data  = "CAPABILITY" *(SP capability) SP "IMAP4rev2"
                   *(SP capability)

RFC4315 (UIDPLUS), RFC9051 (IMAP4rev2):

resp-code-apnd   = "APPENDUID" SP nz-number SP append-uid
resp-code-copy   = "COPYUID" SP nz-number SP uid-set SP uid-set
resp-text-code   =/ resp-code-apnd / resp-code-copy / "UIDNOTSTICKY"

RFC7162 (CONDSTORE):

resp-text-code   =/ "HIGHESTMODSEQ" SP mod-sequence-value /
                    "NOMODSEQ" /
                    "MODIFIED" SP sequence-set

RFC7162 (QRESYNC):

resp-text-code   =/ "CLOSED"

RFC8474: OBJECTID

resp-text-code   =/ "MAILBOXID" SP "(" objectid ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1810

def resp_text_code
  name = resp_text_code__name
  data =
    case name
    when "CAPABILITY"         then resp_code__capability
    when "PERMANENTFLAGS"     then SP? ? flag_perm__list : []
    when "UIDNEXT"            then SP!; nz_number
    when "UIDVALIDITY"        then SP!; nz_number
    when "UNSEEN"             then SP!; nz_number            # rev1 only
    when "APPENDUID"          then SP!; resp_code_apnd__data # rev2, UIDPLUS
    when "COPYUID"            then SP!; resp_code_copy__data # rev2, UIDPLUS
    when "BADCHARSET"         then SP? ? charset__list : []
    when "ALERT", "PARSE", "READ-ONLY", "READ-WRITE", "TRYCREATE",
      "UNAVAILABLE", "AUTHENTICATIONFAILED", "AUTHORIZATIONFAILED",
      "EXPIRED", "PRIVACYREQUIRED", "CONTACTADMIN", "NOPERM", "INUSE",
      "EXPUNGEISSUED", "CORRUPTION", "SERVERBUG", "CLIENTBUG", "CANNOT",
      "LIMIT", "OVERQUOTA", "ALREADYEXISTS", "NONEXISTENT", "CLOSED",
      "NOTSAVED", "UIDNOTSTICKY", "UNKNOWN-CTE", "HASCHILDREN"
    when "NOMODSEQ"           then nil                       # CONDSTORE
    when "HIGHESTMODSEQ"      then SP!; mod_sequence_value   # CONDSTORE
    when "MODIFIED"           then SP!; sequence_set         # CONDSTORE
    when "MAILBOXID"          then SP!; parens__objectid     # RFC8474: OBJECTID
    else
      SP? and text_chars_except_rbra
    end
  ResponseCode.new(name, data)
end

#response

This method is for internal use only.
RFC3501 & RFC9051:

response = *(continue-req / response-data) response-done

For simplicity, response isn’t interpreted as the combination of the three response types, but instead represents any individual server response. Our simplified interpretation is defined as:

response        = continue-req | response_data | response-tagged

n.b: our “response-tagged” definition parses “greeting” too.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 654

def response
  resp = case lookahead!(T_PLUS, T_STAR, *TAG_TOKENS).symbol
         when T_PLUS then continue_req
         when T_STAR then response_data
         else             response_tagged
         end
  accept_spaces # QUIRKY: Ignore trailing space (MS Exchange Server?)
  CRLF!
  EOF!
  resp
end

#response_data

This method is for internal use only.
RFC3501:

response-data = “*” SP (resp-cond-state / resp-cond-bye /

mailbox-data / message-data / capability-data) CRLF
RFC4466:

response-data = “*” SP response-payload CRLF response-payload = resp-cond-state / resp-cond-bye /

mailbox-data / message-data / capability-data

RFC5161 (ENABLE capability):

response-data    =/ "*" SP enable-data CRLF

RFC5255 (LANGUAGE capability)

response-payload =/ language-data

RFC5255 (I18NLEVEL=1 and I18NLEVEL=2 capabilities)

response-payload =/ comparator-data
RFC9051:

response-data = “*” SP (resp-cond-state / resp-cond-bye /

mailbox-data / message-data / capability-data /
enable-data) CRLF
merging in greeting and response-fatal:

greeting = “*” SP (resp-cond-auth / resp-cond-bye) CRLF response-fatal = “*” SP resp-cond-bye CRLF response-data =/ “*” SP (resp-cond-auth / resp-cond-bye) CRLF

removing duplicates, this is simply

response-payload =/ resp-cond-auth

TODO: remove resp-cond-auth and handle greeting separately

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 706

def response_data
  STAR!; SP!
  m = peek_re(RE_RESPONSE_TYPE) or parse_error("unparsable response")
  case m["type"].upcase
  when "OK"         then resp_cond_state__untagged # RFC3501, RFC9051
  when "FETCH"      then message_data__fetch       # RFC3501, RFC9051
  when "EXPUNGE"    then message_data__expunge     # RFC3501, RFC9051
  when "EXISTS"     then mailbox_data__exists      # RFC3501, RFC9051
  when "ESEARCH"    then esearch_response          # RFC4731, RFC9051, etc
  when "VANISHED"   then expunged_resp             # RFC7162
  when "UIDFETCH"   then uidfetch_resp             # (draft) UIDONLY
  when "SEARCH"     then mailbox_data__search      # RFC3501 (obsolete)
  when "CAPABILITY" then capability_data__untagged # RFC3501, RFC9051
  when "FLAGS"      then mailbox_data__flags       # RFC3501, RFC9051
  when "LIST"       then mailbox_data__list        # RFC3501, RFC9051
  when "STATUS"     then mailbox_data__status      # RFC3501, RFC9051
  when "NAMESPACE"  then namespace_response        # RFC2342, RFC9051
  when "ENABLED"    then enable_data               # RFC5161, RFC9051
  when "BAD"        then resp_cond_state__untagged # RFC3501, RFC9051
  when "NO"         then resp_cond_state__untagged # RFC3501, RFC9051
  when "PREAUTH"    then resp_cond_auth            # RFC3501, RFC9051
  when "BYE"        then resp_cond_bye             # RFC3501, RFC9051
  when "RECENT"     then mailbox_data__recent      # RFC3501 (obsolete)
  when "SORT"       then sort_data                 # RFC5256, RFC7162
  when "THREAD"     then thread_data               # RFC5256
  when "QUOTA"      then quota_response            # RFC2087, RFC9208
  when "QUOTAROOT"  then quotaroot_response        # RFC2087, RFC9208
  when "ID"         then id_response               # RFC2971
  when "ACL"        then acl_data                  # RFC4314
  when "LISTRIGHTS" then listrights_data           # RFC4314
  when "MYRIGHTS"   then myrights_data             # RFC4314
  when "METADATA"   then              # RFC5464
  when "LANGUAGE"   then language_data             # RFC5255
  when "COMPARATOR" then comparator_data           # RFC5255
  when "CONVERTED"  then message_data__converted   # RFC5259
  when "LSUB"       then mailbox_data__lsub        # RFC3501 (obsolete)
  when "XLIST"      then mailbox_data__xlist       # deprecated
  when "NOOP"       then response_data__noop
  else                   response_data__unhandled
  end
end

#response_data__ignored Also known as: #response_data__noop

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 766

def response_data__ignored; response_data__unhandled(IgnoredResponse) end

#response_data__noop

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 767

alias response_data__noop     response_data__ignored

#response_data__simple_numeric Also known as: #message_data__expunge, #mailbox_data__exists, #mailbox_data__recent

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 832

def response_data__simple_numeric
  data = nz_number; SP!
  name = tagged_ext_label
  UntaggedResponse.new(name, data, @str)
end

#response_data__unhandled(klass = UntaggedResponse) Also known as: #esearch_response, #expunged_resp, #uidfetch_resp, #listrights_data, #myrights_data, #metadata_resp, #language_data, #comparator_data, #message_data__converted

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 748

def response_data__unhandled(klass = UntaggedResponse)
  num  = number?;          SP?
  type = tagged_ext_label; SP?
  text = remaining_unparsed
  data =
    if num && text then UnparsedNumericResponseData.new(num, text)
    elsif     text then UnparsedData.new(text)
    else                num
    end
  klass.new(type, data, @str)
end

#response_tagged

This method is for internal use only.

RFC3501 & RFC9051:

response-tagged = tag SP resp-cond-state CRLF
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 781

def response_tagged
  TaggedResponse.new(tag, *(SP!; resp_cond_state), @str)
end

#section

This method is for internal use only.

section = “[” [section-spec] “]”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1264

def section
  str = +lbra
  str << section_spec unless peek_rbra?
  str << rbra
end

#section_binary

This method is for internal use only.

section-binary = “[” [section-part] “]”

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1271

def section_binary
  str = +lbra
  str << section_part unless peek_rbra?
  str << rbra
end

#section_spec

This method is for internal use only.

section-spec = section-msgtext / (section-part [“.” section-text]) section-msgtext = “HEADER” /

"HEADER.FIELDS" [".NOT"] SP header-list /
"TEXT"
  ; top-level or MESSAGE/RFC822 or
  ; MESSAGE/GLOBAL part

section-part = nz-number *(“.” nz-number)

; body part reference.
; Allows for accessing nested body parts.

section-text = section-msgtext / “MIME”

; text other than actual body part (headers,
; etc.)

n.b: we could “cheat” here and just grab all text inside the brackets, but literals would need special treatment.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1292

def section_spec
  str = "".b
  str << atom # grabs everything up to "SP header-list" or "]"
  str << " " << header_list if SP?
  str
end

#sequence_set

This method is for internal use only.

sequence-set = (seq-number / seq-range) [“,” sequence-set]

sequence-set    =/ seq-last-command
                    ; Allow for "result of the last command"
                    ; indicator.
seq-last-command   = "$"

note: doesn’t match seq-last-command

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 468

def sequence_set
  str = combine_adjacent(*SEQUENCE_SET_TOKENS)
  if Patterns::SEQUENCE_SET_STR.match?(str)
    SequenceSet[str]
  else
    parse_error("unexpected atom %p, expected sequence-set", str)
  end
end

#sort_data

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1476

alias sort_data mailbox_data__search

#status_att_list

This method is for internal use only.

RFC3501

status-att-list = status-att SP number *(SP status-att SP number)

RFC4466, RFC9051, and RFC3501 Errata

status-att-list = status-att-val *(SP status-att-val)
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1541

def status_att_list
  attrs = [status_att_val]
  while SP? do attrs << status_att_val end
  attrs.to_h
end

#status_att_val

This method is for internal use only.

RFC3501 Errata: status-att-val = (“MESSAGES” SP number) / (“RECENT” SP number) /

("UIDNEXT" SP nz-number) / ("UIDVALIDITY" SP nz-number) /
("UNSEEN" SP number)

RFC4466: status-att-val = (“MESSAGES” SP number) /

("RECENT" SP number) /
("UIDNEXT" SP nz-number) /
("UIDVALIDITY" SP nz-number) /
("UNSEEN" SP number)
;; Extensions to the STATUS responses
;; should extend this production.
;; Extensions should use the generic
;; syntax defined by tagged-ext.

RFC9051: status-att-val = (“MESSAGES” SP number) /

("UIDNEXT" SP nz-number) /
("UIDVALIDITY" SP nz-number) /
("UNSEEN" SP number) /
("DELETED" SP number) /
("SIZE" SP number64)
  ; Extensions to the STATUS responses
  ; should extend this production.
  ; Extensions should use the generic
  ; syntax defined by tagged-ext.

RFC7162: status-att-val =/ “HIGHESTMODSEQ” SP mod-sequence-valzer

;; Extends non-terminal defined in [RFC4466].
;; Value 0 denotes that the mailbox doesn't
;; support persistent mod-sequences
;; as described in Section 3.1.2.2.

RFC7889: status-att-val =/ “APPENDLIMIT” SP (number / nil)

;; status-att-val is defined in RFC 4466

RFC8438: status-att-val =/ “SIZE” SP number64 RFC8474: status-att-val =/ “MAILBOXID” SP “(” objectid “)”

; follows tagged-ext production from [RFC4466]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1586

def status_att_val
  key = tagged_ext_label
  SP!
  val =
    case key
    when "MESSAGES"      then number              # RFC3501, RFC9051
    when "UNSEEN"        then number              # RFC3501, RFC9051
    when "DELETED"       then number              # RFC3501, RFC9051
    when "UIDNEXT"       then nz_number           # RFC3501, RFC9051
    when "UIDVALIDITY"   then nz_number           # RFC3501, RFC9051
    when "RECENT"        then number              # RFC3501 (obsolete)
    when "SIZE"          then number64            # RFC8483, RFC9051
    when "HIGHESTMODSEQ" then mod_sequence_valzer # RFC7162
    when "MAILBOXID"     then parens__objectid    # RFC8474
    else
      number? || ExtensionData.new(tagged_ext_val)
    end
  [key, val]
end

#tag

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 489

def tag;           combine_adjacent(*TAG_TOKENS)           end

#tagged_ext_comp

This method is for internal use only.

tagged-ext-comp = astring /

tagged-ext-comp *(SP tagged-ext-comp) /
"(" tagged-ext-comp ")"
; Extensions that follow this general
; syntax should use nstring instead of
; astring when appropriate in the context
; of the extension.
; Note that a message set or a "number"
; can always be represented as an "atom".
; A URL should be represented as
; a "quoted" string.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 571

def tagged_ext_comp
  vals = []
  while true
    vals << case lookahead!(*ASTRING_TOKENS, T_LPAR).symbol
            when T_LPAR   then lpar; ary = tagged_ext_comp; rpar; ary
            when T_NUMBER then number
            else               astring
            end
    SP? or break
  end
  vals
end

#tagged_ext_simple

This method is for internal use only.

tagged-ext-simple is a subset of atom TODO: recognize sequence-set in the lexer

tagged-ext-simple = sequence-set / number / number64

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 588

def tagged_ext_simple
  number? || sequence_set
end

#tagged_ext_val

This method is for internal use only.

tagged-ext-val = tagged-ext-simple /

"(" [tagged-ext-comp] ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 594

def tagged_ext_val
  if lpar?
    _ = peek_rpar? ? [] : tagged_ext_comp
    rpar
    _
  else
    tagged_ext_simple
  end
end

#text_chars_except_rbra

This method is for internal use only.

1*<any TEXT-CHAR except “]”>

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1841

def text_chars_except_rbra
  match_re(CTEXT_REGEXP, '1*<any TEXT-CHAR except "]">')[0]
end

#thread_data

This method is for internal use only.

RFC5256: THREAD

thread-data     = "THREAD" [SP 1*thread-list]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1480

def thread_data
  name    = label("THREAD")
  threads = []
  if SP?
    threads << thread_list while lookahead_thread_list?
  end
  UntaggedResponse.new(name, threads, @str)
end

#thread_list

This method is for internal use only.

RFC5256: THREAD

thread-list     = "(" (thread-members / thread-nested) ")"
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1494

def thread_list
  lpar
  thread = if lookahead_thread_nested?
             ThreadMember.new(nil, thread_nested)
           else
             thread_members
           end
  rpar
  thread
end

#thread_members

This method is for internal use only.

RFC5256: THREAD

thread-members  = nz-number *(SP nz-number) [SP thread-nested]
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1507

def thread_members
  members = []
  members << nz_number # thread root
  while SP?
    case lookahead!(T_NUMBER, T_LPAR).symbol
    when T_NUMBER then members << nz_number
    else               nested = thread_nested; break
    end
  end
  members.reverse.inject(nested || []) {|subthreads, number|
    [ThreadMember.new(number, subthreads)]
  }.first
end

#thread_nested

This method is for internal use only.

RFC5256: THREAD

thread-nested   = 2*thread-list
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1523

def thread_nested
  nested = [thread_list, thread_list]
  while lookahead_thread_list? do nested << thread_list end
  nested
end

#uid_set

This method is for internal use only.

RFC-4315 (UIDPLUS) or RFC9051 (IMAP4rev2):

uid-set         = (uniqueid / uid-range) *("," uid-set)
uid-range       = (uniqueid ":" uniqueid)
                    ; two uniqueid values and all values
                    ; between these two regardless of order.
                    ; Example: 2:4 and 4:2 are equivalent.
uniqueid        = nz-number
                    ; Strictly ascending
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 2000

def uid_set
  token = match(T_NUMBER, T_ATOM)
  case token.symbol
  when T_NUMBER then [Integer(token.value)]
  when T_ATOM
    token.value.split(",").flat_map {|range|
      range = range.split(":").map {|uniqueid| Integer(uniqueid) }
      range.size == 1 ? range : Range.new(range.min, range.max).to_a
    }
  end
end

#uidfetch_resp(klass = UntaggedResponse)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 771

alias uidfetch_resp           response_data__unhandled

#uniqueid

This method is for internal use only.

Alias for #nz_number.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 637

alias uniqueid    nz_number

#x_gm_id

This method is for internal use only.

valid number ranges are not enforced by parser

a 64-bit unsigned integer and is the decimal equivalent for the ID hex string used in the web interface and the Gmail API.

[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 643

alias x_gm_id     number

#x_gm_label

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1948

def x_gm_label; accept(T_BSLASH) ? atom.capitalize.to_sym : astring end

#x_gm_labels

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/imap/response_parser.rb', line 1951

def x_gm_labels
  lpar; return [] if rpar?
  labels = []
  labels << x_gm_label
  labels << x_gm_label while SP?
  rpar
  labels
end