|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module Net |
| 4 | + class IMAP |
| 5 | + # An "extended search" response (+ESEARCH+). ESearchResult should be |
| 6 | + # returned (instead of SearchResult) by IMAP#search, IMAP#uid_search, |
| 7 | + # IMAP#sort, and IMAP#uid_sort under any of the following conditions: |
| 8 | + # |
| 9 | + # * Return options were specified for IMAP#search or IMAP#uid_search. |
| 10 | + # The server must support a search extension which allows |
| 11 | + # RFC4466[https://www.rfc-editor.org/rfc/rfc4466.html] +return+ options, |
| 12 | + # such as +ESEARCH+, +PARTIAL+, or +IMAP4rev2+. |
| 13 | + # * Return options were specified for IMAP#sort or IMAP#uid_sort. |
| 14 | + # The server must support the +ESORT+ extension |
| 15 | + # {[RFC5267]}[https://www.rfc-editor.org/rfc/rfc5267.html#section-3]. |
| 16 | + # |
| 17 | + # *NOTE:* IMAP#search and IMAP#uid_search do not support +ESORT+ yet. |
| 18 | + # * The server supports +IMAP4rev2+ but _not_ +IMAP4rev1+, or +IMAP4rev2+ |
| 19 | + # has been enabled. +IMAP4rev2+ requires +ESEARCH+ results. |
| 20 | + # |
| 21 | + # Note that some servers may claim to support a search extension which |
| 22 | + # requires an +ESEARCH+ result, such as +PARTIAL+, but still only return a |
| 23 | + # +SEARCH+ result when +return+ options are specified. |
| 24 | + # |
| 25 | + # Some search extensions may result in the server sending ESearchResult |
| 26 | + # responses after the initiating command has completed. Use |
| 27 | + # IMAP#add_response_handler to handle these responses. |
| 28 | + class ESearchResult < Data.define(:tag, :uid, :data) |
| 29 | + def initialize(tag: nil, uid: nil, data: nil) |
| 30 | + tag => String | nil; tag = -tag if tag |
| 31 | + uid => true | false | nil; uid = !!uid |
| 32 | + data => Array | nil; data ||= []; data.freeze |
| 33 | + super |
| 34 | + end |
| 35 | + |
| 36 | + # :call-seq: to_a -> Array of integers |
| 37 | + # |
| 38 | + # When #all contains a SequenceSet of message sequence |
| 39 | + # numbers or UIDs, +to_a+ returns that set as an array of integers. |
| 40 | + # |
| 41 | + # When #all is +nil+, either because the server |
| 42 | + # returned no results or because +ALL+ was not included in |
| 43 | + # the IMAP#search +RETURN+ options, #to_a returns an empty array. |
| 44 | + # |
| 45 | + # Note that SearchResult also implements +to_a+, so it can be used without |
| 46 | + # checking if the server returned +SEARCH+ or +ESEARCH+ data. |
| 47 | + def to_a; all&.numbers || [] end |
| 48 | + |
| 49 | + ## |
| 50 | + # attr_reader: tag |
| 51 | + # |
| 52 | + # The tag string for the command that caused this response to be returned. |
| 53 | + # |
| 54 | + # When +nil+, this response was not caused by a particular command. |
| 55 | + |
| 56 | + ## |
| 57 | + # attr_reader: uid |
| 58 | + # |
| 59 | + # Indicates whether #data in this response refers to UIDs (when +true+) or |
| 60 | + # to message sequence numbers (when +false+). |
| 61 | + |
| 62 | + ## |
| 63 | + alias uid? uid |
| 64 | + |
| 65 | + ## |
| 66 | + # attr_reader: data |
| 67 | + # |
| 68 | + # Search return data, as an array of <tt>[name, value]</tt> pairs. Most |
| 69 | + # return data corresponds to a search +return+ option with the same name. |
| 70 | + # |
| 71 | + # Note that some return data names may be used more than once per result. |
| 72 | + # |
| 73 | + # This data can be more simply retrieved by #min, #max, #all, #count, |
| 74 | + # #modseq, and other methods. |
| 75 | + |
| 76 | + # :call-seq: min -> integer or nil |
| 77 | + # |
| 78 | + # The lowest message number/UID that satisfies the SEARCH criteria. |
| 79 | + # |
| 80 | + # Returns +nil+ when the associated search command has no results, or when |
| 81 | + # the +MIN+ return option wasn't specified. |
| 82 | + # |
| 83 | + # Requires +ESEARCH+ {[RFC4731]}[https://www.rfc-editor.org/rfc/rfc4731.html#section-3.1] or |
| 84 | + # +IMAP4rev2+ {[RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.3.4]. |
| 85 | + def min; data.assoc("MIN")&.last end |
| 86 | + |
| 87 | + # :call-seq: max -> integer or nil |
| 88 | + # |
| 89 | + # The highest message number/UID that satisfies the SEARCH criteria. |
| 90 | + # |
| 91 | + # Returns +nil+ when the associated search command has no results, or when |
| 92 | + # the +MAX+ return option wasn't specified. |
| 93 | + # |
| 94 | + # Requires +ESEARCH+ {[RFC4731]}[https://www.rfc-editor.org/rfc/rfc4731.html#section-3.1] or |
| 95 | + # +IMAP4rev2+ {[RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.3.4]. |
| 96 | + def max; data.assoc("MAX")&.last end |
| 97 | + |
| 98 | + # :call-seq: all -> sequence set or nil |
| 99 | + # |
| 100 | + # A SequenceSet containing all message sequence numbers or UIDs that |
| 101 | + # satisfy the SEARCH criteria. |
| 102 | + # |
| 103 | + # Returns +nil+ when the associated search command has no results, or when |
| 104 | + # the +ALL+ return option was not specified but other return options were. |
| 105 | + # |
| 106 | + # Requires +ESEARCH+ {[RFC4731]}[https://www.rfc-editor.org/rfc/rfc4731.html#section-3.1] or |
| 107 | + # +IMAP4rev2+ {[RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.3.4]. |
| 108 | + # |
| 109 | + # See also: #to_a |
| 110 | + def all; data.assoc("ALL")&.last end |
| 111 | + |
| 112 | + # :call-seq: count -> integer or nil |
| 113 | + # |
| 114 | + # Returns the number of messages that satisfy the SEARCH criteria. |
| 115 | + # |
| 116 | + # Returns +nil+ when the associated search command has no results, or when |
| 117 | + # the +COUNT+ return option wasn't specified. |
| 118 | + # |
| 119 | + # Requires +ESEARCH+ {[RFC4731]}[https://www.rfc-editor.org/rfc/rfc4731.html#section-3.1] or |
| 120 | + # +IMAP4rev2+ {[RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.3.4]. |
| 121 | + def count; data.assoc("COUNT")&.last end |
| 122 | + |
| 123 | + # :call-seq: modseq -> integer or nil |
| 124 | + # |
| 125 | + # The highest +mod-sequence+ of all messages being returned. |
| 126 | + # |
| 127 | + # Returns +nil+ when the associated search command has no results, or when |
| 128 | + # the +MODSEQ+ search criterion wasn't specified. |
| 129 | + # |
| 130 | + # Note that there is no search +return+ option for +MODSEQ+. It will be |
| 131 | + # returned whenever the +CONDSTORE+ extension has been enabled. Using the |
| 132 | + # +MODSEQ+ search criteria will implicitly enable +CONDSTORE+. |
| 133 | + # |
| 134 | + # Requires +CONDSTORE+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html] |
| 135 | + # and +ESEARCH+ {[RFC4731]}[https://www.rfc-editor.org/rfc/rfc4731.html#section-3.2]. |
| 136 | + def modseq; data.assoc("MODSEQ")&.last end |
| 137 | + |
| 138 | + end |
| 139 | + end |
| 140 | +end |
0 commit comments