net-imap 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of net-imap might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49dc46f2744a04f6b151bc033176f2d59dabf04fb1996bba36a87b4b9f0f99b4
4
- data.tar.gz: 411eac8fd696e619f0255d37a83b74b19b3290c68533fded627cd689d1afc57a
3
+ metadata.gz: a871e99f51067e3a509aa5a74fe2c49f4d79496bcec2f21ac50c3c5793d2cdbf
4
+ data.tar.gz: 302c03e65954f9a118d877f97ea2296f34a7f50c8b1299e3e4f8b589cb620880
5
5
  SHA512:
6
- metadata.gz: 3049e6a03f6660c6e7c67c82a9fdb8994a2a0ec3777ca66a6e4941b1a08486e452eb17007e5c666e41a52e34c2c54d057e33aecd6a4b5bac9c522d5f20acfb43
7
- data.tar.gz: 9c7f8e858614748c65a434900f8b6ddba04b9e31578aa9669987803153c31269888abe6baca8ae42c5ecc00287dab2f494de73ac89cf1fb81d44ebfa65d42c5d
6
+ metadata.gz: 85d97c9729220265da03588f175fea22bcdd27d40cd06910ad35bc01ed64bd0c27b2769790464712572166761f3e82fc4eb6330fef64f45cceb0b3e1007f7126
7
+ data.tar.gz: aa18d53b81e57ddfbdde2b8295ca7324f965fa744846fdd756ec4ca1c30e6e72092b106ff454d100f70d1078ee239f2b3e643bd4650606a2fc3b4ab5a2d0cc1f
@@ -153,6 +153,38 @@ module Net
153
153
  end
154
154
  end
155
155
 
156
+ class PartialRange < CommandData # :nodoc:
157
+ uint32_max = 2**32 - 1
158
+ POS_RANGE = 1..uint32_max
159
+ NEG_RANGE = -uint32_max..-1
160
+ Positive = ->{ (_1 in Range) and POS_RANGE.cover?(_1) }
161
+ Negative = ->{ (_1 in Range) and NEG_RANGE.cover?(_1) }
162
+
163
+ def initialize(data:)
164
+ min, max = case data
165
+ in Range
166
+ data.minmax.map { Integer _1 }
167
+ in ResponseParser::Patterns::PARTIAL_RANGE
168
+ data.split(":").map { Integer _1 }.minmax
169
+ else
170
+ raise ArgumentError, "invalid partial range input: %p" % [data]
171
+ end
172
+ data = min..max
173
+ unless data in Positive | Negative
174
+ raise ArgumentError, "invalid partial-range: %p" % [data]
175
+ end
176
+ super
177
+ rescue TypeError, RangeError
178
+ raise ArgumentError, "expected range min/max to be Integers"
179
+ end
180
+
181
+ def formatted = "%d:%d" % data.minmax
182
+
183
+ def send_data(imap, tag)
184
+ imap.__send__(:put_string, formatted)
185
+ end
186
+ end
187
+
156
188
  # *DEPRECATED*. Replaced by SequenceSet.
157
189
  class MessageSet < CommandData # :nodoc:
158
190
  def send_data(imap, tag)
@@ -35,16 +35,16 @@ module Net
35
35
 
36
36
  # :call-seq: to_a -> Array of integers
37
37
  #
38
- # When #all contains a SequenceSet of message sequence
38
+ # When either #all or #partial contains a SequenceSet of message sequence
39
39
  # numbers or UIDs, +to_a+ returns that set as an array of integers.
40
40
  #
41
- # When #all is +nil+, either because the server
42
- # returned no results or because +ALL+ was not included in
41
+ # When both #all and #partial are +nil+, either because the server
42
+ # returned no results or because +ALL+ and +PARTIAL+ were not included in
43
43
  # the IMAP#search +RETURN+ options, #to_a returns an empty array.
44
44
  #
45
45
  # Note that SearchResult also implements +to_a+, so it can be used without
46
46
  # checking if the server returned +SEARCH+ or +ESEARCH+ data.
47
- def to_a; all&.numbers || [] end
47
+ def to_a; all&.numbers || partial&.to_a || [] end
48
48
 
49
49
  ##
50
50
  # attr_reader: tag
@@ -135,6 +135,46 @@ module Net
135
135
  # and +ESEARCH+ {[RFC4731]}[https://www.rfc-editor.org/rfc/rfc4731.html#section-3.2].
136
136
  def modseq; data.assoc("MODSEQ")&.last end
137
137
 
138
+ # Returned by ESearchResult#partial.
139
+ #
140
+ # Requires +PARTIAL+ {[RFC9394]}[https://www.rfc-editor.org/rfc/rfc9394.html]
141
+ # or <tt>CONTEXT=SEARCH</tt>/<tt>CONTEXT=SORT</tt>
142
+ # {[RFC5267]}[https://www.rfc-editor.org/rfc/rfc5267.html]
143
+ #
144
+ # See also: #to_a
145
+ class PartialResult < Data.define(:range, :results)
146
+ def initialize(range:, results:)
147
+ range => Range
148
+ results = SequenceSet[results] unless results.nil?
149
+ super
150
+ end
151
+
152
+ ##
153
+ # method: range
154
+ # :call-seq: range -> range
155
+
156
+ ##
157
+ # method: results
158
+ # :call-seq: results -> sequence set or nil
159
+
160
+ # Converts #results to an array of integers.
161
+ #
162
+ # See also: ESearchResult#to_a.
163
+ def to_a; results&.numbers || [] end
164
+ end
165
+
166
+ # :call-seq: partial -> PartialResult or nil
167
+ #
168
+ # A PartialResult containing a subset of the message sequence numbers or
169
+ # UIDs that satisfy the SEARCH criteria.
170
+ #
171
+ # Requires +PARTIAL+ {[RFC9394]}[https://www.rfc-editor.org/rfc/rfc9394.html]
172
+ # or <tt>CONTEXT=SEARCH</tt>/<tt>CONTEXT=SORT</tt>
173
+ # {[RFC5267]}[https://www.rfc-editor.org/rfc/rfc5267.html]
174
+ #
175
+ # See also: #to_a
176
+ def partial; data.assoc("PARTIAL")&.last end
177
+
138
178
  end
139
179
  end
140
180
  end
@@ -321,6 +321,24 @@ module Net
321
321
  SEQUENCE_SET = /#{SEQUENCE_SET_ITEM}(?:,#{SEQUENCE_SET_ITEM})*/n
322
322
  SEQUENCE_SET_STR = /\A#{SEQUENCE_SET}\z/n
323
323
 
324
+ # partial-range-first = nz-number ":" nz-number
325
+ # ;; Request to search from oldest (lowest UIDs) to
326
+ # ;; more recent messages.
327
+ # ;; A range 500:400 is the same as 400:500.
328
+ # ;; This is similar to <seq-range> from [RFC3501]
329
+ # ;; but cannot contain "*".
330
+ PARTIAL_RANGE_FIRST = /\A(#{NZ_NUMBER}):(#{NZ_NUMBER})\z/n
331
+
332
+ # partial-range-last = MINUS nz-number ":" MINUS nz-number
333
+ # ;; Request to search from newest (highest UIDs) to
334
+ # ;; oldest messages.
335
+ # ;; A range -500:-400 is the same as -400:-500.
336
+ PARTIAL_RANGE_LAST = /\A(-#{NZ_NUMBER}):(-#{NZ_NUMBER})\z/n
337
+
338
+ # partial-range = partial-range-first / partial-range-last
339
+ PARTIAL_RANGE = Regexp.union(PARTIAL_RANGE_FIRST,
340
+ PARTIAL_RANGE_LAST)
341
+
324
342
  # RFC3501:
325
343
  # literal = "{" number "}" CRLF *CHAR8
326
344
  # ; Number represents the number of CHAR8s
@@ -1517,6 +1535,9 @@ module Net
1517
1535
  # From RFC4731 (ESEARCH):
1518
1536
  # search-return-data =/ "MODSEQ" SP mod-sequence-value
1519
1537
  #
1538
+ # From RFC9394 (PARTIAL):
1539
+ # search-return-data =/ ret-data-partial
1540
+ #
1520
1541
  def search_return_data
1521
1542
  label = search_modifier_name; SP!
1522
1543
  value =
@@ -1526,11 +1547,41 @@ module Net
1526
1547
  when "ALL" then sequence_set
1527
1548
  when "COUNT" then number
1528
1549
  when "MODSEQ" then mod_sequence_value # RFC7162: CONDSTORE
1550
+ when "PARTIAL" then ret_data_partial__value # RFC9394: PARTIAL
1529
1551
  else search_return_value
1530
1552
  end
1531
1553
  [label, value]
1532
1554
  end
1533
1555
 
1556
+ # From RFC5267 (CONTEXT=SEARCH, CONTEXT=SORT) and RFC9394 (PARTIAL):
1557
+ # ret-data-partial = "PARTIAL"
1558
+ # SP "(" partial-range SP partial-results ")"
1559
+ def ret_data_partial__value
1560
+ lpar
1561
+ range = partial_range; SP!
1562
+ results = partial_results
1563
+ rpar
1564
+ ESearchResult::PartialResult.new(range, results)
1565
+ end
1566
+
1567
+ # partial-range = partial-range-first / partial-range-last
1568
+ # tagged-ext-simple =/ partial-range-last
1569
+ def partial_range
1570
+ case (str = atom)
1571
+ when Patterns::PARTIAL_RANGE_FIRST, Patterns::PARTIAL_RANGE_LAST
1572
+ min, max = [Integer($1), Integer($2)].minmax
1573
+ min..max
1574
+ else
1575
+ parse_error("unexpected atom %p, expected partial-range", str)
1576
+ end
1577
+ end
1578
+
1579
+ # partial-results = sequence-set / "NIL"
1580
+ # ;; <sequence-set> from [RFC3501].
1581
+ # ;; NIL indicates that no results correspond to
1582
+ # ;; the requested range.
1583
+ def partial_results; NIL? ? nil : sequence_set end
1584
+
1534
1585
  # search-modifier-name = tagged-ext-label
1535
1586
  alias search_modifier_name tagged_ext_label
1536
1587
 
data/lib/net/imap.rb CHANGED
@@ -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]
@@ -723,7 +733,7 @@ module Net
723
733
  # * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
724
734
  #
725
735
  class IMAP < Protocol
726
- VERSION = "0.5.3"
736
+ VERSION = "0.5.4"
727
737
 
728
738
  # Aliases for supported capabilities, to be used with the #enable command.
729
739
  ENABLE_ALIASES = {
@@ -1971,8 +1981,9 @@ module Net
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 @@ module Net
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 @@ module Net
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
  #
@@ -2357,14 +2393,9 @@ module Net
2357
2393
  # Sends a {FETCH command [IMAP4rev1 §6.4.5]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.5]
2358
2394
  # to retrieve data associated with a message in the mailbox.
2359
2395
  #
2360
- # The +set+ parameter is a number or a range between two numbers,
2361
- # or an array of those. The number is a message sequence number,
2362
- # where -1 represents a '*' for use in range notation like 100..-1
2363
- # being interpreted as '100:*'. Beware that the +exclude_end?+
2364
- # property of a Range object is ignored, and the contents of a
2365
- # range are independent of the order of the range endpoints as per
2366
- # the protocol specification, so 1...5, 5..1 and 5...1 are all
2367
- # equivalent to 1..5.
2396
+ # +set+ is the message sequence numbers to fetch, and may be any valid input
2397
+ # to {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
2398
+ # (For UIDs, use #uid_fetch instead.)
2368
2399
  #
2369
2400
  # +attr+ is a list of attributes to fetch; see the documentation
2370
2401
  # for FetchData for a list of valid attributes.
@@ -2374,7 +2405,7 @@ module Net
2374
2405
  #
2375
2406
  # The return value is an array of FetchData.
2376
2407
  #
2377
- # Related: #uid_search, FetchData
2408
+ # Related: #uid_fetch, FetchData
2378
2409
  #
2379
2410
  # ==== For example:
2380
2411
  #
@@ -2403,30 +2434,66 @@ module Net
2403
2434
  # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2404
2435
  # +changedsince+ argument. Using +changedsince+ implicitly enables the
2405
2436
  # +CONDSTORE+ extension.
2406
- def fetch(set, attr, mod = nil, changedsince: nil)
2407
- fetch_internal("FETCH", set, attr, mod, changedsince: changedsince)
2437
+ def fetch(...)
2438
+ fetch_internal("FETCH", ...)
2408
2439
  end
2409
2440
 
2410
2441
  # :call-seq:
2411
- # uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2442
+ # uid_fetch(set, attr, changedsince: nil, partial: nil) -> array of FetchData
2412
2443
  #
2413
2444
  # Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2414
2445
  # to retrieve data associated with a message in the mailbox.
2415
2446
  #
2416
- # Similar to #fetch, but the +set+ parameter contains unique identifiers
2417
- # instead of message sequence numbers.
2447
+ # +set+ is the message UIDs to fetch, and may be any valid input to
2448
+ # {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
2449
+ # (For message sequence numbers, use #fetch instead.)
2418
2450
  #
2451
+ # +attr+ behaves the same as with #fetch.
2419
2452
  # >>>
2420
2453
  # *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
2421
2454
  # part of any +FETCH+ response caused by a +UID+ command, regardless of
2422
2455
  # whether a +UID+ was specified as a message data item to the +FETCH+.
2423
2456
  #
2457
+ # +changedsince+ (optional) behaves the same as with #fetch.
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
+ #
2424
2486
  # Related: #fetch, FetchData
2425
2487
  #
2426
2488
  # ==== Capabilities
2427
- # Same as #fetch.
2428
- def uid_fetch(set, attr, mod = nil, changedsince: nil)
2429
- fetch_internal("UID FETCH", set, attr, mod, changedsince: changedsince)
2489
+ #
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:
@@ -3338,24 +3405,14 @@ module Net
3338
3405
  ]
3339
3406
  return_opts.map {|opt|
3340
3407
  case opt
3341
- when Symbol then opt.to_s
3342
- when Range then partial_range_last_or_seqset(opt)
3343
- else opt
3408
+ when Symbol then opt.to_s
3409
+ when PartialRange::Negative then PartialRange[opt]
3410
+ when Range then SequenceSet[opt]
3411
+ else opt
3344
3412
  end
3345
3413
  }
3346
3414
  end
3347
3415
 
3348
- def partial_range_last_or_seqset(range)
3349
- case [range.begin, range.end]
3350
- in [Integer => first, Integer => last] if first.negative? && last.negative?
3351
- # partial-range-last [RFC9394]
3352
- first <= last or raise DataFormatError, "empty range: %p" % [range]
3353
- "#{first}:#{last}"
3354
- else
3355
- SequenceSet[range]
3356
- end
3357
- end
3358
-
3359
3416
  def search_internal(cmd, ...)
3360
3417
  args, esearch = search_args(...)
3361
3418
  synchronize do
@@ -3382,7 +3439,12 @@ module Net
3382
3439
  end
3383
3440
  end
3384
3441
 
3385
- 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
3386
3448
  if changedsince
3387
3449
  mod ||= []
3388
3450
  mod << "CHANGEDSINCE" << Integer(changedsince)
@@ -3399,9 +3461,9 @@ module Net
3399
3461
  synchronize do
3400
3462
  clear_responses("FETCH")
3401
3463
  if mod
3402
- send_command(cmd, SequenceSet.new(set), attr, mod)
3464
+ send_command(cmd, set, attr, mod)
3403
3465
  else
3404
- send_command(cmd, SequenceSet.new(set), attr)
3466
+ send_command(cmd, set, attr)
3405
3467
  end
3406
3468
  clear_responses("FETCH")
3407
3469
  end
data/rakelib/rfcs.rake CHANGED
@@ -145,6 +145,7 @@ RFCS = {
145
145
  8514 => "IMAP SAVEDATE",
146
146
  8970 => "IMAP PREVIEW",
147
147
  9208 => "IMAP QUOTA, QUOTA=, QUOTASET",
148
+ 9394 => "IMAP PARTIAL",
148
149
 
149
150
  # etc...
150
151
  3629 => "UTF8",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-imap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2024-12-20 00:00:00.000000000 Z
12
+ date: 2024-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-protocol