From f167e3cdd08607d1e487d69e3c4b0444cfd1405d Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 12:31:12 -0500 Subject: [PATCH 01/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?Tagged/Untagged/Continuation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 98 +++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index bac4339a..83103d89 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -10,34 +10,47 @@ class IMAP < Protocol # ready to accept the continuation of a command from the client. The # remainder of this response is a line of text. # - # continue_req ::= "+" SPACE (resp_text / base64) - # - # ==== Fields: - # - # data:: Returns the data (Net::IMAP::ResponseText). - # - # raw_data:: Returns the raw data string. class ContinuationRequest < Struct.new(:data, :raw_data) + ## + # method: data + # :call-seq: data -> ResponseText + # + # Returns a ResponseText object + + ## + # method: raw_data + # :call-seq: raw_data -> string + # + # the raw response data end # Net::IMAP::UntaggedResponse represents untagged responses. # # Data transmitted by the server to the client and status responses # that do not indicate command completion are prefixed with the token - # "*", and are called untagged responses. - # - # response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye / - # mailbox_data / message_data / capability_data) - # - # ==== Fields: + # "*", and are called untagged responses. # - # name:: Returns the name, such as "FLAGS", "LIST", or "FETCH". - # - # data:: Returns the data such as an array of flag symbols, - # a (()) object. - # - # raw_data:: Returns the raw data string. class UntaggedResponse < Struct.new(:name, :data, :raw_data) + ## + # method: name + # :call-seq: name -> string + # + # The uppercase response name, e.g. "FLAGS", "LIST", "FETCH", etc. + + ## + # method: data + # :call-seq: data -> object or nil + # + # The parsed response data, e.g: an array of flag symbols, an array of + # capabilities strings, a ResponseText object, a MailboxList object, a + # FetchData object, a Namespaces object, etc. The response #name + # determines what form the data can take. + + ## + # method: raw_data + # :call-seq: raw_data -> string + # + # The raw response data. end # Net::IMAP::IgnoredResponse represents intentionally ignored responses. @@ -47,10 +60,12 @@ class UntaggedResponse < Struct.new(:name, :data, :raw_data) # # It matches no IMAP standard. # - # ==== Fields: - # - # raw_data:: Returns the raw data string. class IgnoredResponse < Struct.new(:raw_data) + ## + # method: raw_data + # :call-seq: raw_data -> string + # + # The raw response data. end # Net::IMAP::TaggedResponse represents tagged responses. @@ -59,23 +74,30 @@ class IgnoredResponse < Struct.new(:raw_data) # failure of the operation. It is tagged with the same tag as the # client command which began the operation. # - # response_tagged ::= tag SPACE resp_cond_state CRLF - # - # tag ::= 1* - # - # resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text - # - # ==== Fields: - # - # tag:: Returns the tag. - # - # name:: Returns the name, one of "OK", "NO", or "BAD". - # - # data:: Returns the data. See (()). - # - # raw_data:: Returns the raw data string. - # class TaggedResponse < Struct.new(:tag, :name, :data, :raw_data) + ## + # method: tag + # :call-seq: tag -> string + # + # Returns the command tag + + ## + # method: name + # :call-seq: name -> string + # + # Returns the name, one of "OK", "NO", or "BAD". + + ## + # method: data + # :call-seq: data -> ResponseText + # + # Returns a ResponseText object + + ## + # method: raw_data + # :call-seq: raw_data -> string + # + # The raw response data. end # Net::IMAP::ResponseText represents texts of responses. From d4e15e02291d2540ea8b564bc52ca3e984ca0383 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 12:58:19 -0500 Subject: [PATCH 02/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?ResponseText,=20ResponseCode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 58 ++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 83103d89..2267b337 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -101,38 +101,48 @@ class TaggedResponse < Struct.new(:tag, :name, :data, :raw_data) end # Net::IMAP::ResponseText represents texts of responses. - # The text may be prefixed by the response code. # - # resp_text ::= ["[" resp-text-code "]" SP] text - # - # ==== Fields: - # - # code:: Returns the response code. See (()). - # - # text:: Returns the text. + # The text may be prefixed by a ResponseCode. # + # ResponseText is returned from TaggedResponse#data, or from + # UntaggedResponse#data when the response type is a "condition" ("OK", "NO", + # "BAD", "PREAUTH", or "BYE"). class ResponseText < Struct.new(:code, :text) + ## + # method: code + # :call-seq: code -> ResponseCode or nil + # + # Returns a ResponseCode, if the response contains one + + ## + # method: text + # :call-seq: text -> string + # + # Returns the response text, not including any response code end - # Net::IMAP::ResponseCode represents response codes. - # - # resp_text_code ::= "ALERT" / - # "BADCHARSET" [SP "(" astring *(SP astring) ")" ] / - # 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*] - # - # ==== Fields: - # - # name:: Returns the name, such as "ALERT", "PERMANENTFLAGS", or "UIDVALIDITY". + # Net::IMAP::ResponseCode represents response codes. Response codes can be + # retrieved from ResponseText#code and can be included in any "condition" + # response: any TaggedResponse and UntaggedResponse when the response type + # is a "condition" ("OK", "NO", "BAD", "PREAUTH", or "BYE"). # - # data:: Returns the data, if it exists. # class ResponseCode < Struct.new(:name, :data) + ## + # method: name + # :call-seq: name -> string + # + # Returns the response code name, such as "ALERT", "PERMANENTFLAGS", or + # "UIDVALIDITY". + + ## + # method: data + # :call-seq: data -> object or nil + # + # Returns the parsed response code data, e.g: an array of capabilities + # strings, an array of character set strings, a list of permanent flags, + # an Integer, etc. The response #code determines what form the response + # code data can take. end # Net::IMAP::UIDPlusData represents the ResponseCode#data that accompanies From bd0fd4a3ecaed604ff1922ca526ddcf1bff04c31 Mon Sep 17 00:00:00 2001 From: nick evans Date: Sun, 13 Nov 2022 01:02:58 -0500 Subject: [PATCH 03/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20ResponseCode:?= =?UTF-8?q?=20compatibility,=20codes,=20etc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Document backwards-compatibility for unparsed response code data. * Document Net::IMAP#responses behavior. * Document RFC3501 codes. * List RFC5530 codes. --- lib/net/imap/response_data.rb | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 2267b337..625659b5 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -126,6 +126,76 @@ class ResponseText < Struct.new(:code, :text) # response: any TaggedResponse and UntaggedResponse when the response type # is a "condition" ("OK", "NO", "BAD", "PREAUTH", or "BYE"). # + # Some response codes come with additional data which will be parsed by + # Net::IMAP. Others return +nil+ for #data, but are used as a + # machine-readable annotation for the human-readable ResponseText#text in + # the same response. When Net::IMAP does not know how to parse response + # code text, #data returns the unparsed string. + # + # Untagged response code #data is pushed directly onto Net::IMAP#responses, + # keyed by #name, unless it is removed by the command that generated it. + # Use Net::IMAP#add_response_handler to view tagged response codes for + # command methods that do not return their TaggedResponse. + # + # \IMAP extensions may define new codes and the data that comes with them. + # The IANA {IMAP Response + # Codes}[https://www.iana.org/assignments/imap-response-codes/imap-response-codes.xhtml] + # registry has links to specifications for all standard response codes. + # Response codes are backwards compatible: Servers are allowed to send new + # response codes even if the client has not enabled the extension that + # defines them. When unknown response code data is encountered, #data + # will return an unparsed string. + # + # See [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501]] {§7.1, "Server + # Responses - Status + # Responses"}[https://www.rfc-editor.org/rfc/rfc3501#section-7.1] for full + # definitions of the basic set of IMAP4rev1 response codes: + # * +ALERT+, the ResponseText#text contains a special alert that MUST be + # brought to the user's attention. + # * +BADCHARSET+, #data will be an array of charset strings, or +nil+. + # * +CAPABILITY+, #data will be an array of capability strings. + # * +PARSE+, the ResponseText#text presents an error parsing a message's + # \[RFC5322] or [MIME-IMB] headers. + # * +PERMANENTFLAGS+, followed by an array of flags. System flags will be + # symbols, and keyword flags will be strings. See + # rdoc-ref:Net::IMAP@System+flags + # * +READ-ONLY+, the mailbox was selected read-only, or changed to read-only + # * +READ-WRITE+, the mailbox was selected read-write, or changed to + # read-write + # * +TRYCREATE+, when #append or #copy fail because the target mailbox + # doesn't exist. + # * +UIDNEXT+, #data is an Integer, the next UID value of the mailbox. See + # [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501]], + # {§2.3.1.1, "Unique Identifier (UID) Message + # Attribute}[https://www.rfc-editor.org/rfc/rfc3501#section-2.3.1.1]. + # * +UIDVALIDITY+, #data is an Integer, the UID validity value of the + # mailbox See [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501]], + # {§2.3.1.1, "Unique Identifier (UID) Message + # Attribute}[https://www.rfc-editor.org/rfc/rfc3501#section-2.3.1.1]. + # * +UNSEEN+, #data is an Integer, the number of messages which do not have + # the \Seen flag set. + # + # See RFC5530[https://www.rfc-editor.org/rfc/rfc5530], "IMAP Response + # Codes" for the definition of the following response codes, which are all + # machine-readable annotations for the human-readable ResponseText#text, and + # have +nil+ #data of their own: + # * +UNAVAILABLE+ + # * +AUTHENTICATIONFAILED+ + # * +AUTHORIZATIONFAILED+ + # * +EXPIRED+ + # * +PRIVACYREQUIRED+ + # * +CONTACTADMIN+ + # * +NOPERM+ + # * +INUSE+ + # * +EXPUNGEISSUED+ + # * +CORRUPTION+ + # * +SERVERBUG+ + # * +CLIENTBUG+ + # * +CANNOT+ + # * +LIMIT+ + # * +OVERQUOTA+ + # * +ALREADYEXISTS+ + # * +NONEXISTENT+ # class ResponseCode < Struct.new(:name, :data) ## From 878ad67525046a74278acf192fc14c610bfd728f Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 12:59:52 -0500 Subject: [PATCH 04/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?MailboxList=20as=20methods=20[=F0=9F=9A=A7=20fix=20section=20li?= =?UTF-8?q?nks]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. Attempt to link to mailbox attr docs, but rdoc section links are broken. --- lib/net/imap/response_data.rb | 40 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 625659b5..77f26547 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -269,22 +269,36 @@ def uid_mapping end end - # Net::IMAP::MailboxList represents contents of the LIST response. + # Net::IMAP::MailboxList represents contents of the LIST response, + # representing a single mailbox path. # - # mailbox_list ::= "(" #("\Marked" / "\Noinferiors" / - # "\Noselect" / "\Unmarked" / flag_extension) ")" - # SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox - # - # ==== Fields: - # - # attr:: Returns the name attributes. Each name attribute is a symbol - # capitalized by String#capitalize, such as :Noselect (not :NoSelect). - # - # delim:: Returns the hierarchy delimiter. - # - # name:: Returns the mailbox name. + # Net::IMAP#list returns an array of MailboxList objects. # class MailboxList < Struct.new(:attr, :delim, :name) + ## + # method: attr + # :call-seq: attr -> array of Symbols + # + # Returns the name attributes. Each name attribute is a symbol capitalized + # by String#capitalize, such as :Noselect (not :NoSelect). For the + # semantics of each attribute, see: + # * rdoc-ref:Net::IMAP@Basic+Mailbox+Attributes + # * rdoc-ref:Net::IMAP@Mailbox+role+Attributes + # * Net::IMAP@SPECIAL-USE + # * The IANA {IMAP Mailbox Name Attributes + # registry}[https://www.iana.org/assignments/imap-mailbox-name-attributes/imap-mailbox-name-attributes.xhtml] + + ## + # method: delim + # :call-seq: delim -> single character string + # + # Returns the hierarchy delimiter for the mailbox path. + + ## + # method: name + # :call-seq: name -> string + # + # Returns the mailbox name. end # Net::IMAP::MailboxQuota represents contents of GETQUOTA response. From 36c23bd06fc9749b08e03d2cfa34e2c7d31c0d6d Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:00:33 -0500 Subject: [PATCH 05/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?QUOTA=20structs=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 54 ++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 77f26547..f56c8849 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -306,36 +306,50 @@ class MailboxList < Struct.new(:attr, :delim, :name) # specification below, the delimiter used with the "#" construct is a # single space (SPACE). # - # quota_list ::= "(" #quota_resource ")" + # Net:IMAP#getquota returns an array of MailboxQuota objects. # - # quota_resource ::= atom SPACE number SPACE number - # - # quota_response ::= "QUOTA" SPACE astring SPACE quota_list - # - # ==== Fields: - # - # mailbox:: The mailbox with the associated quota. - # - # usage:: Current storage usage of the mailbox. - # - # quota:: Quota limit imposed on the mailbox. + # Net::IMAP#getquotaroot returns an array containing both MailboxQuotaRoot + # and MailboxQuota objects. # class MailboxQuota < Struct.new(:mailbox, :usage, :quota) + ## + # method: mailbox + # :call-seq: mailbox -> string + # + # The mailbox with the associated quota. + + ## + # method: usage + # :call-seq: usage -> Integer + # + # Current storage usage of the mailbox. + + ## + # method: quota + # :call-seq: quota -> Integer + # + # Quota limit imposed on the mailbox. + # end # Net::IMAP::MailboxQuotaRoot represents part of the GETQUOTAROOT # response. (GETQUOTAROOT can also return Net::IMAP::MailboxQuota.) # - # quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring) - # - # ==== Fields: - # - # mailbox:: The mailbox with the associated quota. - # - # quotaroots:: Zero or more quotaroots that affect the quota on the - # specified mailbox. + # Net::IMAP#getquotaroot returns an array containing both MailboxQuotaRoot + # and MailboxQuota objects. # class MailboxQuotaRoot < Struct.new(:mailbox, :quotaroots) + ## + # method: mailbox + # :call-seq: mailbox -> string + # + # The mailbox with the associated quota. + + ## + # method: mailbox + # :call-seq: quotaroots -> array of strings + # + # Zero or more quotaroots that affect the quota on the specified mailbox. end # Net::IMAP::MailboxACLItem represents the response from GETACL. From e1be7488ed785e4c44a10a918c7ce186105406c7 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:01:05 -0500 Subject: [PATCH 06/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?MailboxACLItem=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index f56c8849..6fbd60ba 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -354,21 +354,29 @@ class MailboxQuotaRoot < Struct.new(:mailbox, :quotaroots) # Net::IMAP::MailboxACLItem represents the response from GETACL. # - # acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights) - # - # identifier ::= astring - # - # rights ::= astring - # - # ==== Fields: - # - # user:: Login name that has certain rights to the mailbox - # that was specified with the getacl command. - # - # rights:: The access rights the indicated user has to the - # mailbox. + # Net::IMAP#getacl returns an array of MailboxACLItem objects. # + # ==== Required capability + # +ACL+ - described in [ACL[https://tools.ietf.org/html/rfc4314]] class MailboxACLItem < Struct.new(:user, :rights, :mailbox) + ## + # method: mailbox + # :call-seq: mailbox -> string + # + # The mailbox to which the indicated #user has the specified #rights. + + ## + # method: user + # :call-seq: user -> string + # + # Login name that has certain #rights to the #mailbox that was specified + # with the getacl command. + + ## + # method: rights + # :call-seq: rights -> string + # + # The access rights the indicated #user has to the #mailbox. end # Net::IMAP::Namespace represents a single [RFC-2342] namespace. From 46488ec47f03dd0cd54d74f3874fcc5107df8fec Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:01:46 -0500 Subject: [PATCH 07/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?namespace=20structs=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 66 ++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 6fbd60ba..83599535 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -379,39 +379,55 @@ class MailboxACLItem < Struct.new(:user, :rights, :mailbox) # The access rights the indicated #user has to the #mailbox. end - # Net::IMAP::Namespace represents a single [RFC-2342] namespace. + # Net::IMAP::Namespace represents a single namespace contained inside a + # NAMESPACE response. # - # Namespace = nil / "(" 1*( "(" string SP (<"> QUOTED_CHAR <"> / - # nil) *(Namespace_Response_Extension) ")" ) ")" - # - # Namespace_Response_Extension = SP string SP "(" string *(SP string) - # ")" - # - # ==== Fields: - # - # prefix:: Returns the namespace prefix string. - # delim:: Returns nil or the hierarchy delimiter character. - # extensions:: Returns a hash of extension names to extension flag arrays. + # Returned by Net::IMAP#namespace, contained inside a Namespaces object. # class Namespace < Struct.new(:prefix, :delim, :extensions) + ## + # method: prefix + # :call-seq: prefix -> string + # + # Returns the namespace prefix string. + + ## + # method: delim + # :call-seq: delim -> single character string or nil + # + # Returns a hierarchy delimiter character, if it exists. + + ## + # method: extensions + # :call-seq: extensions -> Hash[String, Array[String]] + # + # A hash of parameters mapped to arrays of strings, for extensibility. + # Extension parameter semantics would be defined by the extension. end - # Net::IMAP::Namespaces represents the response from [RFC-2342] NAMESPACE. + # Net::IMAP::Namespaces represents a +NAMESPACE+ server response, which + # contains lists of #personal, #shared, and #other namespaces. # - # Namespace_Response = "*" SP "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) - # - # ==== Fields: - # - # personal:: Returns an array of Personal Net::IMAP::Namespace objects. - # other:: Returns an array of Other Users' Net::IMAP::Namespace objects. - # shared:: Returns an array of Shared Net::IMAP::Namespace objects. + # Net::IMAP#namespace returns a Namespaces object. # class Namespaces < Struct.new(:personal, :other, :shared) + ## + # method: personal + # :call-seq: personal -> array of Namespace + # + # Returns an array of Personal Namespace objects. + + ## + # method: other + # :call-seq: other -> array of Namespace + # + # Returns an array of Other Users' Namespace objects. + + ## + # method: shared + # :call-seq: shared -> array of Namespace + # + # Returns an array of Shared Namespace objects. end # Net::IMAP::StatusData represents the contents of the STATUS response. From 7dd04114ef26134bb8bb5e2ca222a47bf369430e Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:02:19 -0500 Subject: [PATCH 08/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?StatusData=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 83599535..c92bddcb 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -432,14 +432,20 @@ class Namespaces < Struct.new(:personal, :other, :shared) # Net::IMAP::StatusData represents the contents of the STATUS response. # - # ==== Fields: - # - # mailbox:: Returns the mailbox name. - # - # attr:: Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT", - # "UIDVALIDITY", "UNSEEN". Each value is a number. - # + # Net::IMAP#status returns the contents of #attr. class StatusData < Struct.new(:mailbox, :attr) + ## + # method: mailbox + # :call-seq: mailbox -> string + # + # The mailbox name. + + ## + # method: attr + # :call-seq: attr -> Hash[String, Integer] + # + # A hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT", + # "UIDVALIDITY", "UNSEEN". Each value is a number. end # Net::IMAP::FetchData represents the contents of the FETCH response. From a90e0498edf93898b04fe01a48956ef35a820e71 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:08:03 -0500 Subject: [PATCH 09/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?FetchData=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. Expand the attr hash documentation, to provide more examples. Add more data item details from the RFCs. --- lib/net/imap/response_data.rb | 229 ++++++++++++++++++++++++++++------ 1 file changed, 193 insertions(+), 36 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index c92bddcb..da602aa3 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -448,51 +448,208 @@ class StatusData < Struct.new(:mailbox, :attr) # "UIDVALIDITY", "UNSEEN". Each value is a number. end - # Net::IMAP::FetchData represents the contents of the FETCH response. + # Net::IMAP::FetchData represents the contents of a FETCH response. # - # ==== Fields: + # Net::IMAP#fetch and Net::IMAP#uid_fetch both return an array of + # FetchData objects. + # + # === Fetch attributes # - # seqno:: Returns the message sequence number. - # (Note: not the unique identifier, even for the UID command response.) - # - # attr:: Returns a hash. Each key is a data item name, and each value is - # its value. - # - # The current data items are: - # - # [BODY] - # A form of BODYSTRUCTURE without extension data. - # [BODY[
]<>] - # A string expressing the body contents of the specified section. - # [BODYSTRUCTURE] - # An object that describes the [MIME-IMB] body structure of a message. - # See Net::IMAP::BodyTypeBasic, Net::IMAP::BodyTypeText, - # Net::IMAP::BodyTypeMessage, Net::IMAP::BodyTypeMultipart. - # [ENVELOPE] - # A Net::IMAP::Envelope object that describes the envelope - # structure of a message. - # [FLAGS] - # A array of flag symbols that are set for this message. Flag symbols - # are capitalized by String#capitalize. - # [INTERNALDATE] - # A string representing the internal date of the message. - # [RFC822] - # Equivalent to +BODY[]+. - # [RFC822.HEADER] - # Equivalent to +BODY.PEEK[HEADER]+. - # [RFC822.SIZE] - # A number expressing the [RFC-822] size of the message. - # [RFC822.TEXT] - # Equivalent to +BODY[TEXT]+. - # [UID] - # A number expressing the unique identifier of the message. + #-- + # TODO: merge branch with accessor methods for each type of attr. Then + # move nearly all of the +attr+ documentation onto the appropriate + # accessor methods. + #++ + # + # Each key of the #attr hash is the data item name for the fetched value. + # Each data item represents a message attribute, part of one, or an + # interpretation of one. #seqno is not a message attribute. Most message + # attributes are static and must never change for a given [server, + # account, mailbox, UIDVALIDITY, UID] tuple. A few message attributes + # can be dynamically changed, e.g. using the {STORE + # command}[rdoc-ref:Net::IMAP#store]. # # See {[IMAP4rev1] §7.4.2}[https://www.rfc-editor.org/rfc/rfc3501.html#section-7.4.2] # and {[IMAP4rev2] §7.5.2}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.5.2] # for full description of the standard fetch response data items, and # Net::IMAP@Message+envelope+and+body+structure for other relevant RFCs. # + # ==== Static fetch data items + # + # The static data items + # defined by [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501.html]] are: + # + # ["UID"] + # A number expressing the unique identifier of the message. + # + # ["BODY[]", "BODY[]<#{offset}>"] + # The [RFC5322[https://tools.ietf.org/html/rfc5322]] expression of the + # entire message, as a string. + # + # If +offset+ is specified, this returned string is a substring of the + # entire contents, starting at that origin octet. This means that + # BODY[]<0> MAY be truncated, but BODY[] is NEVER + # truncated. + # + # Messages can be parsed using the "mail" gem. + # + # [Note] + # When fetching BODY.PEEK[#{specifier}], the data will be + # returned in BODY[#{specifier}], without the +PEEK+. This is + # true for all of the BODY[...] attribute forms. + # + # ["BODY[HEADER]", "BODY[HEADER]<#{offset}>"] + # The [RFC5322[https://tools.ietf.org/html/rfc5322]] header of the + # message. + # + # Message headers can be parsed using the "mail" gem. + # + # ["BODY[HEADER.FIELDS (#{fields.join(" ")})]",] + # ["BODY[HEADER.FIELDS (#{fields.join(" ")})]<#{offset}>"] + # When field names are given, the subset contains only the header fields + # that matches one of the names in the list. The field names are based + # on what was requested, not on what was returned. + # + # ["BODY[HEADER.FIELDS.NOT (#{fields.join(" ")})]",] + # ["BODY[HEADER.FIELDS.NOT (#{fields.join(" ")})]<#{offset}>"] + # When the HEADER.FIELDS.NOT is used, the subset is all of the + # fields that do not match any names in the list. + # + # ["BODY[TEXT]", "BODY[TEXT]<#{offset}>"] + # The text body of the message, omitting + # the [RFC5322[https://tools.ietf.org/html/rfc5322]] header. + # + # ["BODY[#{part}]", "BODY[#{part}]<#{offset}>"] + # The text of a particular body section, if it was fetched. + # + # Multiple part specifiers will be joined with ".". Numeric + # part specifiers refer to the MIME part number, counting up from +1+. + # Messages that don't use MIME, or MIME messages that are not multipart + # and don't hold an encapsulated message, only have a part +1+. + # + # 8-bit textual data is permitted if + # a [CHARSET[https://tools.ietf.org/html/rfc2978]] identifier is part of + # the body parameter parenthesized list for this section. See + # BodyTypeBasic. + # + # MESSAGE/RFC822 or MESSAGE/GLOBAL message, or a subset of the header, if + # it was fetched. + # + # ["BODY[#{part}.HEADER]",] + # ["BODY[#{part}.HEADER]<#{offset}>",] + # ["BODY[#{part}.HEADER.FIELDS.NOT (#{fields.join(" ")})]",] + # ["BODY[#{part}.HEADER.FIELDS.NOT (#{fields.join(" ")})]<#{offset}>",] + # ["BODY[#{part}.TEXT]",] + # ["BODY[#{part}.TEXT]<#{offset}>",] + # ["BODY[#{part}.MIME]",] + # ["BODY[#{part}.MIME]<#{offset}>"] + # +HEADER+, HEADER.FIELDS, HEADER.FIELDS.NOT, and + # TEXT can be prefixed by numeric part specifiers, if it refers + # to a part of type message/rfc822 or message/global. + # + # +MIME+ refers to the [MIME-IMB[https://tools.ietf.org/html/rfc2045]] + # header for this part. + # + # ["BODY"] + # A form of +BODYSTRUCTURE+, without any extension data. + # + # ["BODYSTRUCTURE"] + # Returns a BodyStructure object that describes + # the [MIME-IMB[https://tools.ietf.org/html/rfc2045]] body structure of + # a message, if it was fetched. + # + # ["ENVELOPE"] + # An Envelope object that describes the envelope structure of a message. + # See the documentation for Envelope for a description of the envelope + # structure attributes. + # + # ["INTERNALDATE"] + # The internal date and time of the message on the server. This is not + # the date and time in + # the [RFC5322[https://tools.ietf.org/html/rfc5322]] header, but rather + # a date and time which reflects when the message was received. + # + # ["RFC822.SIZE"] + # A number expressing the [RFC5322[https://tools.ietf.org/html/rfc5322]] + # size of the message. + # + # [Note] + # \IMAP was originally developed for the older RFC-822 standard, and + # as a consequence several fetch items in \IMAP incorporate "RFC822" + # in their name. With the exception of +RFC822.SIZE+, there are more + # modern replacements; for example, the modern version of + # +RFC822.HEADER+ is BODY.PEEK[HEADER]. In all cases, + # "RFC822" should be interpreted as a reference to the + # updated [RFC5322[https://tools.ietf.org/html/rfc5322]] standard. + # + # ["RFC822"] + # Semantically equivalent to BODY[]. + # ["RFC822.HEADER"] + # Semantically equivalent to BODY[HEADER]. + # ["RFC822.TEXT"] + # Semantically equivalent to BODY[TEXT]. + # + # [Note:] + # >>> + # Additional static fields are defined in \IMAP extensions and + # [IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]], but + # Net::IMAP can't parse them yet. + # + #-- + # "BINARY[#{section_binary}]<#{offset}>":: TODO... + # "BINARY.SIZE[#{sectionbinary}]":: TODO... + # "EMAILID":: TODO... + # "THREADID":: TODO... + # "SAVEDATE":: TODO... + #++ + # + # ==== Dynamic message attributes + # The only dynamic item defined + # by [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]] is: + # ["FLAGS"] + # An array of flags that are set for this message. System flags are + # symbols that have been capitalized by String#capitalize. Keyword + # flags are strings and their case is not changed. + # + # \IMAP extensions define new dynamic fields, e.g.: + # + # ["MODSEQ"] + # The modification sequence number associated with this IMAP message. + # + # Requires the [CONDSTORE[https://tools.ietf.org/html/rfc7162]] + # server {capability}[rdoc-ref:Net::IMAP#capability]. + # + # [Note:] + # >>> + # Additional dynamic fields are defined in \IMAP extensions, but + # Net::IMAP can't parse them yet. + # + #-- + # "ANNOTATE":: TODO... + # "PREVIEW":: TODO... + #++ + # class FetchData < Struct.new(:seqno, :attr) + ## + # method: seqno + # :call-seq: seqno -> Integer + # + # The message sequence number. + # + # [Note] + # This is never the unique identifier (UID), not even for the + # Net::IMAP#uid_fetch result. If it was returned, the UID is available + # from attr["UID"]. + + ## + # method: attr + # :call-seq: attr -> hash + # + # A hash. Each key is specifies a message attribute, and the value is the + # corresponding data item. + # + # See rdoc-ref:FetchData@Fetch+attributes for descriptions of possible + # values. end # Net::IMAP::Envelope represents envelope structures of messages. From 7ac35f4aa0f2671c784a88b801051de51d1d64e5 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:10:00 -0500 Subject: [PATCH 10/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?Envelope=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 86 ++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index da602aa3..10cbef48 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -654,27 +654,11 @@ class FetchData < Struct.new(:seqno, :attr) # Net::IMAP::Envelope represents envelope structures of messages. # - # ==== Fields: - # - # date:: Returns a string that represents the date. - # - # subject:: Returns a string that represents the subject. - # - # from:: Returns an array of Net::IMAP::Address that represents the from. - # - # sender:: Returns an array of Net::IMAP::Address that represents the sender. - # - # reply_to:: Returns an array of Net::IMAP::Address that represents the reply-to. - # - # to:: Returns an array of Net::IMAP::Address that represents the to. - # - # cc:: Returns an array of Net::IMAP::Address that represents the cc. - # - # bcc:: Returns an array of Net::IMAP::Address that represents the bcc. - # - # in_reply_to:: Returns a string that represents the in-reply-to. - # - # message_id:: Returns a string that represents the message-id. + # [Note] + # When the #sender and #reply_to fields are absent or empty, they will + # return the same value as #from. Also, fields may return values that are + # invalid for well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] + # messages when the message is malformed or a draft message. # # See [{IMAP4rev1 §7.4.2}[https://www.rfc-editor.org/rfc/rfc3501.html#section-7.4.2]] # and [{IMAP4rev2 §7.5.2}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.5.2]] @@ -683,6 +667,66 @@ class FetchData < Struct.new(:seqno, :attr) # class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to, :to, :cc, :bcc, :in_reply_to, :message_id) + ## + # method: date + # call-seq: date -> string + # + # Returns a string that represents the +Date+ header. + + ## + # method: subject + # call-seq: subject -> string or nil + # + # Returns a string that represents the +Subject+ header, if it is present. + + ## + # method: from + # call-seq: from -> array of Net::IMAP::Address or nil + # + # Returns an array of Address that represents the +From+ header. + + ## + # method: sender + # call-seq: sender -> array of Net::IMAP::Address or nil + # + # Returns an array of Address that represents the +Sender+ header. + + ## + # method: reply_to + # call-seq: reply_to -> array of Net::IMAP::Address or nil + # + # Returns an array of Address that represents the Reply-To + # header. + + ## + # method: to + # call-seq: to -> array of Net::IMAP::Address + # + # Returns an array of Address that represents the +To+ header. + + ## + # method: cc + # call-seq: cc -> array of Net::IMAP::Address + # + # Returns an array of Address that represents the +Cc+ header. + + ## + # method: bcc + # call-seq: bcc -> array of Net::IMAP::Address + # + # Returns an array of Address that represents the +Bcc+ header. + + ## + # method: in_reply_to + # call-seq: in_reply_to -> string + # + # Returns a string that represents the In-Reply-To header. + + ## + # method: message_id + # call-seq: message_id -> string + # + # Returns a string that represents the Message-ID. end # From 582043a20f7955360c86c649e9d144cb5cfdbbb6 Mon Sep 17 00:00:00 2001 From: nick evans Date: Sun, 13 Nov 2022 01:06:54 -0500 Subject: [PATCH 11/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20Envelope:=20nil?= =?UTF-8?q?/empty/default=20semantics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/imap/response_data.rb | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 10cbef48..efe08846 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -672,24 +672,50 @@ class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to, # call-seq: date -> string # # Returns a string that represents the +Date+ header. + # + # [Note] + # For a well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] + # message, the #date field must not be +nil+. However it can be +nil+ + # for a malformed or draft message. ## # method: subject # call-seq: subject -> string or nil # # Returns a string that represents the +Subject+ header, if it is present. + # + # [Note] + # Servers should return +nil+ when the header is absent and an empty + # string when it is present but empty. Some servers may return a +nil+ + # envelope member in the "present but empty" case. Clients should treat + # +nil+ and empty string as identical. ## # method: from # call-seq: from -> array of Net::IMAP::Address or nil # # Returns an array of Address that represents the +From+ header. + # + # If the +From+ header is absent, or is present but empty, the server + # returns +nil+ for this envelope field. + # + # [Note] + # For a well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] + # message, the #from field must not be +nil+. However it can be +nil+ + # for a malformed or draft message. ## # method: sender # call-seq: sender -> array of Net::IMAP::Address or nil # # Returns an array of Address that represents the +Sender+ header. + # + # [Note] + # If the Sender header is absent, or is present but empty, the + # server sets this field to be the same value as #from. Therefore, in a + # well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] message, + # the #sender envelope field must not be +nil+. However it can be + # +nil+ for a malformed or draft message. ## # method: reply_to @@ -697,6 +723,13 @@ class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to, # # Returns an array of Address that represents the Reply-To # header. + # + # [Note] + # If the Reply-To header is absent, or is present but empty, + # the server sets this field to be the same value as #from. Therefore, + # in a well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] + # message, the #reply_to envelope field must not be +nil+. However it + # can be +nil+ for a malformed or draft message. ## # method: to @@ -721,12 +754,32 @@ class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to, # call-seq: in_reply_to -> string # # Returns a string that represents the In-Reply-To header. + # + # [Note] + # For a well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] + # message, the #in_reply_to field, if present, must not be empty. But + # it can still return an empty string for malformed messages. + # + # Servers should return +nil+ when the header is absent and an empty + # string when it is present but empty. Some servers may return a +nil+ + # envelope member in the "present but empty" case. Clients should treat + # +nil+ and empty string as identical. ## # method: message_id # call-seq: message_id -> string # # Returns a string that represents the Message-ID. + # + # [Note] + # For a well-formed [RFC5322[https://tools.ietf.org/html/rfc5322]] + # message, the #message_id field, if present, must not be empty. But it + # can still return an empty string for malformed messages. + # + # Servers should return +nil+ when the header is absent and an empty + # string when it is present but empty. Some servers may return a +nil+ + # envelope member in the "present but empty" case. Clients should treat + # +nil+ and empty string as identical. end # From e03291faa478e2788abbbe0813815184d9d708e4 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:10:23 -0500 Subject: [PATCH 12/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?Address=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 55 +++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index efe08846..ab96e247 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -782,23 +782,48 @@ class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to, # +nil+ and empty string as identical. end - # - # Net::IMAP::Address represents electronic mail addresses. - # - # ==== Fields: - # - # name:: Returns the phrase from [RFC-822] mailbox. - # - # route:: Returns the route from [RFC-822] route-addr. - # - # mailbox:: nil indicates end of [RFC-822] group. - # If non-nil and host is nil, returns [RFC-822] group name. - # Otherwise, returns [RFC-822] local-part. - # - # host:: nil indicates [RFC-822] group syntax. - # Otherwise, returns [RFC-822] domain name. + # Net::IMAP::Address represents an electronic mail address, which has been + # parsed into its component parts by the server. Address objects are + # returned within Envelope fields. # class Address < Struct.new(:name, :route, :mailbox, :host) + ## + # method: name + # :call-seq: name -> string or nil + # + # Returns the [RFC5322[https://tools.ietf.org/html/rfc5322]] address + # +display-name+ (or the mailbox +phrase+ in the RFC-822 grammar). + + ## + # method: route + # :call-seq: route -> string or nil + # + # Returns the route from RFC-822 route-addr. + # + # Note:: Generating this obsolete route addressing syntax is not allowed + # by [RFC5322[https://tools.ietf.org/html/rfc5322]]. However, + # addresses with this syntax must still be accepted and parsed. + + ## + # method: mailbox + # :call-seq: mailbox -> string or nil + # + # Returns the [RFC5322[https://tools.ietf.org/html/rfc5322]] address + # +local-part+, if #host is not +nil+. + # + # When #host is +nil+, this returns + # an [RFC5322[https://tools.ietf.org/html/rfc5322]] group name and a +nil+ + # mailbox indicates the end of a group. + + ## + # method: host + # :call-seq: host -> string or nil + # + # Returns the [RFC5322[https://tools.ietf.org/html/rfc5322]] addr-spec + # +domain+ name. + # + # +nil+ indicates [RFC5322[https://tools.ietf.org/html/rfc5322]] group + # syntax. end # From fbd4a39222ebbdb865d2d96ae3ea3a17bf3925be Mon Sep 17 00:00:00 2001 From: nick evans Date: Sun, 13 Nov 2022 01:07:27 -0500 Subject: [PATCH 13/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20Address=20"grou?= =?UTF-8?q?p=20syntax"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/imap/response_data.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index ab96e247..94451422 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -786,6 +786,14 @@ class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to, # parsed into its component parts by the server. Address objects are # returned within Envelope fields. # + # === Group syntax + # + # When the #host field is +nil+, this is a special form of address structure + # that indicates the [RFC5322[https://tools.ietf.org/html/rfc5322]] group + # syntax. If the #mailbox name field is also +nil+, this is an end-of-group + # marker (semicolon in RFC-822 syntax). If the #mailbox name field is + # non-+NIL+, this is the start of a group marker, and the mailbox #name + # field holds the group name phrase. class Address < Struct.new(:name, :route, :mailbox, :host) ## # method: name From 2613bd31f4a3aff231231b1ca2e8bad24911b116 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:10:41 -0500 Subject: [PATCH 14/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?ContentDisposition=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. * Link to the appropriate RFC(s). --- lib/net/imap/response_data.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 94451422..a909f637 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -834,17 +834,22 @@ class Address < Struct.new(:name, :route, :mailbox, :host) # syntax. end - # # Net::IMAP::ContentDisposition represents Content-Disposition fields. # - # ==== Fields: - # - # dsp_type:: Returns the disposition type. - # - # param:: Returns a hash that represents parameters of the Content-Disposition - # field. - # class ContentDisposition < Struct.new(:dsp_type, :param) + ## + # method: dsp_type + # :call-seq: dsp_type -> string + # + # Returns the content disposition type, as defined by + # [DISPOSITION[https://tools.ietf.org/html/rfc2183]]. + + ## + # method: param + # :call-seq: param -> hash + # + # Returns a hash representing parameters of the Content-Disposition + # field, as defined by [DISPOSITION[https://tools.ietf.org/html/rfc2183]]. end # Net::IMAP::ThreadMember represents a thread-node returned From 2822e2f81d1f5c9b364f7afe9d87326434c7cee2 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:11:28 -0500 Subject: [PATCH 15/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?ThreadMember=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. --- lib/net/imap/response_data.rb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index a909f637..b68736d0 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -855,14 +855,19 @@ class ContentDisposition < Struct.new(:dsp_type, :param) # Net::IMAP::ThreadMember represents a thread-node returned # by Net::IMAP#thread. # - # ==== Fields: - # - # seqno:: The sequence number of this message. - # - # children:: An array of Net::IMAP::ThreadMember objects for mail - # items that are children of this in the thread. - # class ThreadMember < Struct.new(:seqno, :children) + ## + # method: seqno + # :call-seq: seqno -> Integer + # + # The message sequence number. + + ## + # method: children + # :call-seq: children -> array of ThreadMember + # + # An array of Net::IMAP::ThreadMember objects for mail items that are + # children of this in the thread. end # Net::IMAP::BodyTypeBasic represents basic body structures of messages. From 435b7be3f1a57e4176b6abe300ca8b0fb687ad66 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:12:06 -0500 Subject: [PATCH 16/17] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20?= =?UTF-8?q?BodyType=20structs=20as=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move struct field docs from the class to methods inside the class. * Remove ABNF comments. * Add type information to the call-seq or the method rdoc text. * Link to the data type(s) that are returned, when possible. Add warnings to BodyTypeAttachment and BodyTypeExtension. BodyTypeText and BodyTypeMessage link to BodyTypeBasic for documentation of common fields. Link to relevant RFCs where relevant. Update formatting. --- lib/net/imap/response_data.rb | 368 ++++++++++++++++++++++++++-------- 1 file changed, 282 insertions(+), 86 deletions(-) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index b68736d0..c1049c7c 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -870,37 +870,9 @@ class ThreadMember < Struct.new(:seqno, :children) # children of this in the thread. end - # Net::IMAP::BodyTypeBasic represents basic body structures of messages. - # - # ==== Fields: - # - # media_type:: Returns the content media type name as defined in [MIME-IMB]. - # - # subtype:: Returns the content subtype name as defined in [MIME-IMB]. - # - # param:: Returns a hash that represents parameters as defined in [MIME-IMB]. - # - # content_id:: Returns a string giving the content id as defined in [MIME-IMB]. - # - # description:: Returns a string giving the content description as defined in - # [MIME-IMB]. - # - # encoding:: Returns a string giving the content transfer encoding as defined in - # [MIME-IMB]. - # - # size:: Returns a number giving the size of the body in octets. - # - # md5:: Returns a string giving the body MD5 value as defined in [MD5]. - # - # disposition:: Returns a Net::IMAP::ContentDisposition object giving - # the content disposition. - # - # language:: Returns a string or an array of strings giving the body - # language value as defined in [LANGUAGE-TAGS]. - # - # extension:: Returns extension data. - # - # multipart?:: Returns false. + # Net::IMAP::BodyTypeBasic represents basic body structures of messages and + # message parts, unless they have a Content-Type that is handled by + # BodyTypeText, BodyTypeMessage, or BodyTypeMultipart. # # See {[IMAP4rev1] §7.4.2}[https://www.rfc-editor.org/rfc/rfc3501.html#section-7.4.2] # and {[IMAP4rev2] §7.5.2}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.5.2-4.9] @@ -912,26 +884,133 @@ class BodyTypeBasic < Struct.new(:media_type, :subtype, :description, :encoding, :size, :md5, :disposition, :language, :extension) + + ## + # method: media_type + # :call-seq: media_type -> string + # + # The top-level media type as defined in + # [MIME-IMB[https://tools.ietf.org/html/rfc2045]]. + + ## + # method: subtype + # :call-seq: subtype -> string + # + # The media subtype name as defined in + # [MIME-IMB[https://tools.ietf.org/html/rfc2045]]. + + ## + # method: param + # :call-seq: param -> string + # + # Returns a hash that represents parameters as defined in + # [MIME-IMB[https://tools.ietf.org/html/rfc2045]]. + + ## + # method: content_id + # :call-seq: content_id -> string + # + # Returns a string giving the content id as defined + # in [MIME-IMB[https://tools.ietf.org/html/rfc2045]] + # {§7}[https://tools.ietf.org/html/rfc2045#section-7]. + + ## + # method: description + # :call-seq: description -> string + # + # Returns a string giving the content description as defined + # in [MIME-IMB[https://tools.ietf.org/html/rfc2045]] + # {§8}[https://tools.ietf.org/html/rfc2045#section-8]. + + ## + # method: encoding + # :call-seq: encoding -> string + # + # Returns a string giving the content transfer encoding as defined + # in [MIME-IMB[https://tools.ietf.org/html/rfc2045]] + # {§6}[https://tools.ietf.org/html/rfc2045#section-6]. + + ## + # method: size + # :call-seq: size -> integer + # + # Returns a number giving the size of the body in octets. + + ## + # method: md5 + # :call-seq: md5 -> string + # + # Returns a string giving the body MD5 value as defined in + # [MD5[https://tools.ietf.org/html/rfc1864]]. + + ## + # method: disposition + # :call-seq: disposition -> ContentDisposition + # + # Returns a ContentDisposition object giving the content + # disposition, as defined by + # [DISPOSITION[https://tools.ietf.org/html/rfc2183]]. + + ## + # method: language + # :call-seq: language -> string + # + # Returns a string or an array of strings giving the body + # language value as defined in + # [LANGUAGE-TAGS[https://www.rfc-editor.org/info/rfc3282]]. + + #-- + ## + # method: location + # :call-seq: location -> string + # + # A string list giving the body content URI as defined in + # [LOCATION[https://www.rfc-editor.org/info/rfc2557]]. + #++ + + ## + # method: extension + # :call-seq: extension -> string + # + # Returns extension data. The +BODYSTRUCTURE+ fetch attribute + # contains extension data, but +BODY+ does not. + + ## + # :call-seq: multipart? -> false + # + # BodyTypeBasic is not used for multipart MIME parts. def multipart? return false end - # Obsolete: use +subtype+ instead. Calling this will - # generate a warning message to +stderr+, then return - # the value of +subtype+. + # :call-seq: media_subtype -> subtype + # + # >>> + # [Obsolete] + # Use +subtype+ instead. Calling this will generate a warning message + # to +stderr+, then return the value of +subtype+. + #-- + # TODO: why not just keep this as an alias? Would "media_subtype" be used + # for something else? + #++ def media_subtype warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1) return subtype end end - # Net::IMAP::BodyTypeText represents TEXT body structures of messages. + # Net::IMAP::BodyTypeText represents the body structures of messages and + # message parts, when Content-Type is text/*. # - # ==== Fields: - # - # lines:: Returns the size of the body in text lines. - # - # And Net::IMAP::BodyTypeText has all fields of Net::IMAP::BodyTypeBasic. + # BodyTypeText contains all of the fields of BodyTypeBasic. See + # BodyTypeBasic for documentation of the following: + # * {media_type}[rdoc-ref:BodyTypeBasic#media_type] + # * subtype[rdoc-ref:BodyTypeBasic#subtype] + # * param[rdoc-ref:BodyTypeBasic#param] + # * {content_id}[rdoc-ref:BodyTypeBasic#content_id] + # * description[rdoc-ref:BodyTypeBasic#description] + # * encoding[rdoc-ref:BodyTypeBasic#encoding] + # * size[rdoc-ref:BodyTypeBasic#size] # class BodyTypeText < Struct.new(:media_type, :subtype, :param, :content_id, @@ -939,6 +1018,17 @@ class BodyTypeText < Struct.new(:media_type, :subtype, :lines, :md5, :disposition, :language, :extension) + + ## + # method: lines + # :call-seq: lines -> Integer + # + # Returns the size of the body in text lines. + + ## + # :call-seq: multipart? -> false + # + # BodyTypeText is not used for multipart MIME parts. def multipart? return false end @@ -952,15 +1042,19 @@ def media_subtype end end - # Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages. + # Net::IMAP::BodyTypeMessage represents the body structures of messages and + # message parts, when Content-Type is message/rfc822 or + # message/global. # - # ==== Fields: - # - # envelope:: Returns a Net::IMAP::Envelope giving the envelope structure. - # - # body:: Returns an object giving the body structure. - # - # And Net::IMAP::BodyTypeMessage has all methods of Net::IMAP::BodyTypeText. + # BodyTypeMessage contains all of the fields of BodyTypeBasic. See + # BodyTypeBasic for documentation of the following fields: + # * {media_type}[rdoc-ref:BodyTypeBasic#media_type] + # * subtype[rdoc-ref:BodyTypeBasic#subtype] + # * param[rdoc-ref:BodyTypeBasic#param] + # * {content_id}[rdoc-ref:BodyTypeBasic#content_id] + # * description[rdoc-ref:BodyTypeBasic#description] + # * encoding[rdoc-ref:BodyTypeBasic#encoding] + # * size[rdoc-ref:BodyTypeBasic#size] # class BodyTypeMessage < Struct.new(:media_type, :subtype, :param, :content_id, @@ -968,6 +1062,23 @@ class BodyTypeMessage < Struct.new(:media_type, :subtype, :envelope, :body, :lines, :md5, :disposition, :language, :extension) + + ## + # method: envelope + # :call-seq: envelope -> Envelope + # + # Returns a Net::IMAP::Envelope giving the envelope structure. + + ## + # method: body + # :call-seq: body -> BodyStructure + # + # Returns a Net::IMAP::BodyStructure for the message's body structure. + + ## + # :call-seq: multipart? -> false + # + # BodyTypeMessage is not used for multipart MIME parts. def multipart? return false end @@ -981,57 +1092,134 @@ def media_subtype end end - # Net::IMAP::BodyTypeAttachment represents attachment body structures - # of messages. - # - # ==== Fields: - # - # media_type:: Returns the content media type name. - # - # subtype:: Returns +nil+. - # - # param:: Returns a hash that represents parameters. - # - # multipart?:: Returns false. - # - class BodyTypeAttachment < Struct.new(:media_type, :subtype, - :param) + # === WARNING + # BodyTypeAttachment represents a body-fld-dsp that is + # incorrectly in a position where the IMAP4rev1 grammar expects a nested + # +body+ structure. + # + # >>> + # \IMAP body structures are parenthesized lists and assign their fields + # positionally, so missing fields change the intepretation of all + # following fields. Buggy \IMAP servers sometimes leave fields missing + # rather than empty, which inevitably confuses parsers. + # BodyTypeAttachment was an attempt to parse a common type of buggy body + # structure without crashing. + # + # Currently, when Net::IMAP::ResponseParser sees "attachment" as the first + # entry in a body-type-1part, which is where the MIME type should + # be, it uses BodyTypeAttachment to capture the rest. "attachment" is not + # a valid MIME type, but _is_ a common Content-Disposition. What + # might have happened was that buggy server could not parse the message + # (which might have been incorrectly formatted) and output a + # body-type-dsp where a Net::IMAP::ResponseParser expected to see + # a +body+. + # + # A future release will replace this, probably with a ContentDisposition + # nested inside another body structure object, maybe BodyTypeBasic, or + # perhaps a new body structure class that represents any unparsable body + # structure. + # + class BodyTypeAttachment < Struct.new(:dsp_type, :_unused_, :param) + + # *invalid for BodyTypeAttachment* + def media_type + warn(<<~WARN, uplevel: 1) + BodyTypeAttachment#media_type is obsolete. Use dsp_type instead. + WARN + dsp_type + end + + # *invalid for BodyTypeAttachment* + def subtype + warn("BodyTypeAttachment#subtype is obsolete.\n", uplevel: 1) + nil + end + + ## + # method: dsp_type + # :call-seq: dsp_type -> string + # + # Returns the content disposition type, as defined by + # [DISPOSITION[https://tools.ietf.org/html/rfc2183]]. + + ## + # method: param + # :call-seq: param -> hash + # + # Returns a hash representing parameters of the Content-Disposition + # field, as defined by [DISPOSITION[https://tools.ietf.org/html/rfc2183]]. + + ## def multipart? return false end end - # Net::IMAP::BodyTypeMultipart represents multipart body structures - # of messages. - # - # ==== Fields: - # - # media_type:: Returns the content media type name as defined in [MIME-IMB]. - # - # subtype:: Returns the content subtype name as defined in [MIME-IMB]. - # - # parts:: Returns multiple parts. - # - # param:: Returns a hash that represents parameters as defined in [MIME-IMB]. - # - # disposition:: Returns a Net::IMAP::ContentDisposition object giving - # the content disposition. - # - # language:: Returns a string or an array of strings giving the body - # language value as defined in [LANGUAGE-TAGS]. - # - # extension:: Returns extension data. - # - # multipart?:: Returns true. - # + # Net::IMAP::BodyTypeMultipart represents body structures of messages and + # message parts, when Content-Type is multipart/*. class BodyTypeMultipart < Struct.new(:media_type, :subtype, :parts, :param, :disposition, :language, :extension) + + ## + # method: media_type + # call-seq: media_type -> "multipart" + # + # BodyTypeMultipart is only used with multipart/* media types. + + ## + # method: subtype + # call-seq: subtype -> string + # + # Returns the content subtype name + # as defined in [MIME-IMB[https://tools.ietf.org/html/rfc2045]]. + + ## + # method: parts + # call-seq: parts -> array of BodyStructure objects + # + # Returns an array with a BodyStructure object for each part contained in + # this part. + + ## + # method: param + # call-seq: param -> hash + # + # Returns a hash that represents parameters + # as defined in [MIME-IMB[https://tools.ietf.org/html/rfc2045]]. + + ## + # method: disposition + # call-seq: disposition -> ContentDisposition + # + # Returns a Net::IMAP::ContentDisposition object giving the content + # disposition. + + ## + # method: language + # :call-seq: language -> string + # + # Returns a string or an array of strings giving the body + # language value as defined in + # [LANGUAGE-TAGS[https://www.rfc-editor.org/info/rfc3282]]. + + ## + # method: extension + # call-seq: extension -> array + # + # Returns extension data as an array of numbers strings, and nested + # arrays (of numbers, strings, etc). + + ## + # :call-seq: multipart? -> true + # + # BodyTypeMultipart is used for multipart MIME parts. def multipart? return true end + ## # Obsolete: use +subtype+ instead. Calling this will # generate a warning message to +stderr+, then return # the value of +subtype+. @@ -1041,6 +1229,14 @@ def media_subtype end end + # === WARNING: + # >>> + # BodyTypeExtension is (incorrectly) used for message/* parts + # (besides message/rfc822, which correctly uses BodyTypeMessage). + # + # A future release will replace this class with: + # * BodyTypeMessage for message/rfc822 and message/global + # * BodyTypeBasic for any other message/* class BodyTypeExtension < Struct.new(:media_type, :subtype, :params, :content_id, :description, :encoding, :size) From 7e73b62766b4754bbbda4b63e01c093a7137d4e5 Mon Sep 17 00:00:00 2001 From: nick evans Date: Sun, 13 Nov 2022 01:05:15 -0500 Subject: [PATCH 17/17] =?UTF-8?q?=E2=9C=A8=20Add=20BodyStructure=20mixin?= =?UTF-8?q?=20to=20bodystruct=20structs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can be used for documentation, `case` statements and pattern matching, and functionality common to all `BodyType*` structs. --- lib/net/imap/response_data.rb | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index c1049c7c..c8bd7fa5 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -870,6 +870,37 @@ class ThreadMember < Struct.new(:seqno, :children) # children of this in the thread. end + # Net::IMAP::BodyStructure is included by all of the structs that can be + # returned from a "BODYSTRUCTURE" or "BODY" + # FetchData#attr value. Although these classes don't share a base class, + # this module can be used to pattern match all of them. + # + # See {[IMAP4rev1] §7.4.2}[https://www.rfc-editor.org/rfc/rfc3501.html#section-7.4.2] + # and {[IMAP4rev2] §7.5.2}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.5.2-4.9] + # for full description of all +BODYSTRUCTURE+ fields, and also + # Net::IMAP@Message+envelope+and+body+structure for other relevant RFCs. + # + # === Classes that include BodyStructure + # BodyTypeBasic:: Represents any message parts that are not handled by + # BodyTypeText, BodyTypeMessage, or BodyTypeMultipart. + # BodyTypeText:: Used by text/* parts. Contains all of the + # BodyTypeBasic fields. + # BodyTypeMessage:: Used by message/rfc822 and + # message/global parts. Contains all of the + # BodyTypeBasic fields. Other message/* types + # should use BodyTypeBasic. + # BodyTypeMultipart:: for multipart/* parts + # + # ==== Deprecated BodyStructure classes + # The following classes represent invalid server responses or parser bugs: + # BodyTypeExtension:: parser bug: used for message/* where + # BodyTypeBasic should have been used. + # BodyTypeAttachment:: server bug: some servers sometimes return the + # "Content-Disposition: attachment" data where the + # entire body structure for a message part is expected. + module BodyStructure + end + # Net::IMAP::BodyTypeBasic represents basic body structures of messages and # message parts, unless they have a Content-Type that is handled by # BodyTypeText, BodyTypeMessage, or BodyTypeMultipart. @@ -884,6 +915,7 @@ class BodyTypeBasic < Struct.new(:media_type, :subtype, :description, :encoding, :size, :md5, :disposition, :language, :extension) + include BodyStructure ## # method: media_type @@ -1018,6 +1050,7 @@ class BodyTypeText < Struct.new(:media_type, :subtype, :lines, :md5, :disposition, :language, :extension) + include BodyStructure ## # method: lines @@ -1062,6 +1095,7 @@ class BodyTypeMessage < Struct.new(:media_type, :subtype, :envelope, :body, :lines, :md5, :disposition, :language, :extension) + include BodyStructure ## # method: envelope @@ -1120,6 +1154,7 @@ def media_subtype # structure. # class BodyTypeAttachment < Struct.new(:dsp_type, :_unused_, :param) + include BodyStructure # *invalid for BodyTypeAttachment* def media_type @@ -1161,6 +1196,7 @@ class BodyTypeMultipart < Struct.new(:media_type, :subtype, :parts, :param, :disposition, :language, :extension) + include BodyStructure ## # method: media_type @@ -1240,6 +1276,8 @@ def media_subtype class BodyTypeExtension < Struct.new(:media_type, :subtype, :params, :content_id, :description, :encoding, :size) + include BodyStructure + def multipart? return false end