@@ -534,6 +534,11 @@ module Net
534
534
# See FetchData#emailid and FetchData#emailid.
535
535
# - Updates #status with support for the +MAILBOXID+ status attribute.
536
536
#
537
+ # ==== RFC9394: +PARTIAL+
538
+ # - Updates #search, #uid_search with the +PARTIAL+ return option which adds
539
+ # ESearchResult#partial return data.
540
+ # - Updates #uid_fetch with the +partial+ modifier.
541
+ #
537
542
# == References
538
543
#
539
544
# [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]]::
@@ -701,6 +706,11 @@ module Net
701
706
# Gondwana, B., Ed., "IMAP Extension for Object Identifiers",
702
707
# RFC 8474, DOI 10.17487/RFC8474, September 2018,
703
708
# <https://www.rfc-editor.org/info/rfc8474>.
709
+ # [PARTIAL[https://www.rfc-editor.org/info/rfc9394]]::
710
+ # Melnikov, A., Achuthan, A., Nagulakonda, V., and L. Alves,
711
+ # "IMAP PARTIAL Extension for Paged SEARCH and FETCH", RFC 9394,
712
+ # DOI 10.17487/RFC9394, June 2023,
713
+ # <https://www.rfc-editor.org/info/rfc9394>.
704
714
#
705
715
# === IANA registries
706
716
# * {IMAP Capabilities}[http://www.iana.org/assignments/imap4-capabilities]
@@ -1971,8 +1981,9 @@ def uid_expunge(uid_set)
1971
1981
# the server to return an ESearchResult instead of a SearchResult, but some
1972
1982
# servers disobey this requirement. <em>Requires an extended search
1973
1983
# capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
1974
- # See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
1975
- # and {"Return options"}[rdoc-ref:#search@Return+options], below.
1984
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation] and
1985
+ # {"Supported return options"}[rdoc-ref:#search@Supported+return+options],
1986
+ # below.
1976
1987
#
1977
1988
# +charset+ is the name of the {registered character
1978
1989
# set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
@@ -2082,33 +2093,58 @@ def uid_expunge(uid_set)
2082
2093
# <em>*WARNING:* This is vulnerable to injection attacks when external
2083
2094
# inputs are used.</em>
2084
2095
#
2085
- # ==== Return options
2096
+ # ==== Supported return options
2086
2097
#
2087
2098
# For full definitions of the standard return options and return data, see
2088
2099
# the relevant RFCs.
2089
2100
#
2090
- # ===== +ESEARCH+ or +IMAP4rev2+
2091
- #
2092
- # The following return options require either +ESEARCH+ or +IMAP4rev2+.
2093
- # See [{RFC4731 §3.1}[https://rfc-editor.org/rfc/rfc4731#section-3.1]] or
2094
- # [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]].
2095
- #
2096
2101
# [+ALL+]
2097
2102
# Returns ESearchResult#all with a SequenceSet of all matching sequence
2098
2103
# numbers or UIDs. This is the default, when return options are empty.
2099
2104
#
2100
2105
# For compatibility with SearchResult, ESearchResult#to_a returns an
2101
2106
# Array of message sequence numbers or UIDs.
2107
+ #
2108
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2109
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2110
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2111
+ #
2102
2112
# [+COUNT+]
2103
2113
# Returns ESearchResult#count with the number of matching messages.
2114
+ #
2115
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2116
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2117
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2118
+ #
2104
2119
# [+MAX+]
2105
2120
# Returns ESearchResult#max with the highest matching sequence number or
2106
2121
# UID.
2122
+ #
2123
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2124
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2125
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2126
+ #
2107
2127
# [+MIN+]
2108
2128
# Returns ESearchResult#min with the lowest matching sequence number or
2109
2129
# UID.
2110
2130
#
2111
- # ===== +CONDSTORE+
2131
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2132
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2133
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2134
+ #
2135
+ # [+PARTIAL+ _range_]
2136
+ # Returns ESearchResult#partial with a SequenceSet of a subset of
2137
+ # matching sequence numbers or UIDs, as selected by _range_. As with
2138
+ # sequence numbers, the first result is +1+: <tt>1..500</tt> selects the
2139
+ # first 500 search results (in mailbox order), <tt>501..1000</tt> the
2140
+ # second 500, and so on. _range_ may also be negative: <tt>-500..-1</tt>
2141
+ # selects the last 500 search results.
2142
+ #
2143
+ # <em>Requires either the <tt>CONTEXT=SEARCH</tt> or +PARTIAL+ capabability.</em>
2144
+ # {[RFC5267]}[https://rfc-editor.org/rfc/rfc5267]
2145
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2146
+ #
2147
+ # ===== +MODSEQ+ return data
2112
2148
#
2113
2149
# ESearchResult#modseq return data does not have a corresponding return
2114
2150
# option. Instead, it is returned if the +MODSEQ+ search key is used or
@@ -2120,8 +2156,8 @@ def uid_expunge(uid_set)
2120
2156
#
2121
2157
# {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
2122
2158
# defines standard syntax for search extensions. Net::IMAP allows sending
2123
- # unknown search return options and will parse unknown search extensions'
2124
- # return values into ExtensionData. Please note that this is an
2159
+ # unsupported search return options and will parse unsupported search
2160
+ # extensions' return values into ExtensionData. Please note that this is an
2125
2161
# intentionally _unstable_ API. Future releases may return different
2126
2162
# (incompatible) objects, <em>without deprecation or warning</em>.
2127
2163
#
@@ -2398,12 +2434,12 @@ def uid_search(...)
2398
2434
# {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2399
2435
# +changedsince+ argument. Using +changedsince+ implicitly enables the
2400
2436
# +CONDSTORE+ extension.
2401
- def fetch ( set , attr , mod = nil , changedsince : nil )
2402
- fetch_internal ( "FETCH" , set , attr , mod , changedsince : changedsince )
2437
+ def fetch ( ... )
2438
+ fetch_internal ( "FETCH" , ... )
2403
2439
end
2404
2440
2405
2441
# :call-seq:
2406
- # uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2442
+ # uid_fetch(set, attr, changedsince: nil, partial: nil ) -> array of FetchData
2407
2443
#
2408
2444
# Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2409
2445
# to retrieve data associated with a message in the mailbox.
@@ -2420,13 +2456,44 @@ def fetch(set, attr, mod = nil, changedsince: nil)
2420
2456
#
2421
2457
# +changedsince+ (optional) behaves the same as with #fetch.
2422
2458
#
2459
+ # +partial+ is an optional range to limit the number of results returned.
2460
+ # It's useful when +set+ contains an unknown number of messages.
2461
+ # <tt>1..500</tt> returns the first 500 messages in +set+ (in mailbox
2462
+ # order), <tt>501..1000</tt> the second 500, and so on. +partial+ may also
2463
+ # be negative: <tt>-500..-1</tt> selects the last 500 messages in +set+.
2464
+ # <em>Requires the +PARTIAL+ capabability.</em>
2465
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2466
+ #
2467
+ # For example:
2468
+ #
2469
+ # # Without partial, the size of the results may be unknown beforehand:
2470
+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
2471
+ # # ... maybe wait for a long time ... and allocate a lot of memory ...
2472
+ # results.size # => 0..2**32-1
2473
+ # process results # may also take a long time and use a lot of memory...
2474
+ #
2475
+ # # Using partial, the results may be paginated:
2476
+ # loop do
2477
+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
2478
+ # partial: 1..500)
2479
+ # # fetch should return quickly and allocate little memory
2480
+ # results.size # => 0..500
2481
+ # break if results.empty?
2482
+ # next_uid_to_fetch = results.last.uid + 1
2483
+ # process results
2484
+ # end
2485
+ #
2423
2486
# Related: #fetch, FetchData
2424
2487
#
2425
2488
# ==== Capabilities
2426
2489
#
2427
- # Same as #fetch.
2428
- def uid_fetch ( set , attr , mod = nil , changedsince : nil )
2429
- fetch_internal ( "UID FETCH" , set , attr , mod , changedsince : changedsince )
2490
+ # The server's capabilities must include +PARTIAL+
2491
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394] in order to use the
2492
+ # +partial+ argument.
2493
+ #
2494
+ # Otherwise, the same as #fetch.
2495
+ def uid_fetch ( ...)
2496
+ fetch_internal ( "UID FETCH" , ...)
2430
2497
end
2431
2498
2432
2499
# :call-seq:
@@ -3372,7 +3439,12 @@ def search_internal(cmd, ...)
3372
3439
end
3373
3440
end
3374
3441
3375
- def fetch_internal ( cmd , set , attr , mod = nil , changedsince : nil )
3442
+ def fetch_internal ( cmd , set , attr , mod = nil , partial : nil , changedsince : nil )
3443
+ set = SequenceSet [ set ]
3444
+ if partial
3445
+ mod ||= [ ]
3446
+ mod << "PARTIAL" << PartialRange [ partial ]
3447
+ end
3376
3448
if changedsince
3377
3449
mod ||= [ ]
3378
3450
mod << "CHANGEDSINCE" << Integer ( changedsince )
@@ -3389,9 +3461,9 @@ def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
3389
3461
synchronize do
3390
3462
clear_responses ( "FETCH" )
3391
3463
if mod
3392
- send_command ( cmd , SequenceSet . new ( set ) , attr , mod )
3464
+ send_command ( cmd , set , attr , mod )
3393
3465
else
3394
- send_command ( cmd , SequenceSet . new ( set ) , attr )
3466
+ send_command ( cmd , set , attr )
3395
3467
end
3396
3468
clear_responses ( "FETCH" )
3397
3469
end
0 commit comments