net-imap 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
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