From 18b1f3c4456b24340fb4cfe6ecfd02f9c6d81a5e Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 14 Nov 2022 13:12:06 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9A=20Document=20fields=20for=20BodyTy?= =?UTF-8?q?pe=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)