net-imap 0.5.1 → 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 +4 -4
- data/README.md +7 -3
- data/docs/styles.css +65 -14
- data/lib/net/imap/command_data.rb +48 -46
- data/lib/net/imap/data_lite.rb +225 -0
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/response_data.rb +2 -0
- data/lib/net/imap/response_parser/parser_utils.rb +5 -0
- data/lib/net/imap/response_parser.rb +137 -2
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +531 -226
- data/rakelib/rfcs.rake +1 -0
- metadata +8 -5
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
module Net
|
4
4
|
class IMAP < Protocol
|
5
|
+
autoload :ESearchResult, "#{__dir__}/esearch_result"
|
5
6
|
autoload :FetchData, "#{__dir__}/fetch_data"
|
6
7
|
autoload :SearchResult, "#{__dir__}/search_result"
|
7
8
|
autoload :SequenceSet, "#{__dir__}/sequence_set"
|
9
|
+
autoload :VanishedData, "#{__dir__}/vanished_data"
|
8
10
|
|
9
11
|
# Net::IMAP::ContinuationRequest represents command continuation requests.
|
10
12
|
#
|
@@ -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
|
@@ -769,8 +787,6 @@ module Net
|
|
769
787
|
def response_data__ignored; response_data__unhandled(IgnoredResponse) end
|
770
788
|
alias response_data__noop response_data__ignored
|
771
789
|
|
772
|
-
alias esearch_response response_data__unhandled
|
773
|
-
alias expunged_resp response_data__unhandled
|
774
790
|
alias uidfetch_resp response_data__unhandled
|
775
791
|
alias listrights_data response_data__unhandled
|
776
792
|
alias myrights_data response_data__unhandled
|
@@ -842,6 +858,20 @@ module Net
|
|
842
858
|
alias mailbox_data__exists response_data__simple_numeric
|
843
859
|
alias mailbox_data__recent response_data__simple_numeric
|
844
860
|
|
861
|
+
# The name for this is confusing, because it *replaces* EXPUNGE
|
862
|
+
# >>>
|
863
|
+
# expunged-resp = "VANISHED" [SP "(EARLIER)"] SP known-uids
|
864
|
+
def expunged_resp
|
865
|
+
name = label "VANISHED"; SP!
|
866
|
+
earlier = if lpar? then label("EARLIER"); rpar; SP!; true else false end
|
867
|
+
uids = known_uids
|
868
|
+
data = VanishedData[uids, earlier]
|
869
|
+
UntaggedResponse.new name, data, @str
|
870
|
+
end
|
871
|
+
|
872
|
+
# TODO: replace with uid_set
|
873
|
+
alias known_uids sequence_set
|
874
|
+
|
845
875
|
# RFC3501 & RFC9051:
|
846
876
|
# msg-att = "(" (msg-att-dynamic / msg-att-static)
|
847
877
|
# *(SP (msg-att-dynamic / msg-att-static)) ")"
|
@@ -1468,6 +1498,111 @@ module Net
|
|
1468
1498
|
end
|
1469
1499
|
alias sort_data mailbox_data__search
|
1470
1500
|
|
1501
|
+
# esearch-response = "ESEARCH" [search-correlator] [SP "UID"]
|
1502
|
+
# *(SP search-return-data)
|
1503
|
+
# ;; Note that SEARCH and ESEARCH responses
|
1504
|
+
# ;; SHOULD be mutually exclusive,
|
1505
|
+
# ;; i.e., only one of the response types
|
1506
|
+
# ;; should be
|
1507
|
+
# ;; returned as a result of a command.
|
1508
|
+
# esearch-response = "ESEARCH" [search-correlator] [SP "UID"]
|
1509
|
+
# *(SP search-return-data)
|
1510
|
+
# ; ESEARCH response replaces SEARCH response
|
1511
|
+
# ; from IMAP4rev1.
|
1512
|
+
# search-correlator = SP "(" "TAG" SP tag-string ")"
|
1513
|
+
def esearch_response
|
1514
|
+
name = label("ESEARCH")
|
1515
|
+
tag = search_correlator if peek_str?(" (")
|
1516
|
+
uid = peek_re?(/\G UID\b/i) && (SP!; label("UID"); true)
|
1517
|
+
data = []
|
1518
|
+
data << search_return_data while SP?
|
1519
|
+
esearch = ESearchResult.new(tag, uid, data)
|
1520
|
+
UntaggedResponse.new(name, esearch, @str)
|
1521
|
+
end
|
1522
|
+
|
1523
|
+
# From RFC4731 (ESEARCH):
|
1524
|
+
# search-return-data = "MIN" SP nz-number /
|
1525
|
+
# "MAX" SP nz-number /
|
1526
|
+
# "ALL" SP sequence-set /
|
1527
|
+
# "COUNT" SP number /
|
1528
|
+
# search-ret-data-ext
|
1529
|
+
# ; All return data items conform to
|
1530
|
+
# ; search-ret-data-ext syntax.
|
1531
|
+
# search-ret-data-ext = search-modifier-name SP search-return-value
|
1532
|
+
# search-modifier-name = tagged-ext-label
|
1533
|
+
# search-return-value = tagged-ext-val
|
1534
|
+
#
|
1535
|
+
# From RFC4731 (ESEARCH):
|
1536
|
+
# search-return-data =/ "MODSEQ" SP mod-sequence-value
|
1537
|
+
#
|
1538
|
+
# From RFC9394 (PARTIAL):
|
1539
|
+
# search-return-data =/ ret-data-partial
|
1540
|
+
#
|
1541
|
+
def search_return_data
|
1542
|
+
label = search_modifier_name; SP!
|
1543
|
+
value =
|
1544
|
+
case label
|
1545
|
+
when "MIN" then nz_number
|
1546
|
+
when "MAX" then nz_number
|
1547
|
+
when "ALL" then sequence_set
|
1548
|
+
when "COUNT" then number
|
1549
|
+
when "MODSEQ" then mod_sequence_value # RFC7162: CONDSTORE
|
1550
|
+
when "PARTIAL" then ret_data_partial__value # RFC9394: PARTIAL
|
1551
|
+
else search_return_value
|
1552
|
+
end
|
1553
|
+
[label, value]
|
1554
|
+
end
|
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
|
+
|
1585
|
+
# search-modifier-name = tagged-ext-label
|
1586
|
+
alias search_modifier_name tagged_ext_label
|
1587
|
+
|
1588
|
+
# search-return-value = tagged-ext-val
|
1589
|
+
# ; Data for the returned search option.
|
1590
|
+
# ; A single "nz-number"/"number"/"number64" value
|
1591
|
+
# ; can be returned as an atom (i.e., without
|
1592
|
+
# ; quoting). A sequence-set can be returned
|
1593
|
+
# ; as an atom as well.
|
1594
|
+
def search_return_value; ExtensionData.new(tagged_ext_val) end
|
1595
|
+
|
1596
|
+
# search-correlator = SP "(" "TAG" SP tag-string ")"
|
1597
|
+
def search_correlator
|
1598
|
+
SP!; lpar; label("TAG"); SP!; tag = tag_string; rpar
|
1599
|
+
tag
|
1600
|
+
end
|
1601
|
+
|
1602
|
+
# tag-string = astring
|
1603
|
+
# ; <tag> represented as <astring>
|
1604
|
+
alias tag_string astring
|
1605
|
+
|
1471
1606
|
# RFC5256: THREAD
|
1472
1607
|
# thread-data = "THREAD" [SP 1*thread-list]
|
1473
1608
|
def thread_data
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class IMAP < Protocol
|
5
|
+
|
6
|
+
# Net::IMAP::VanishedData represents the contents of a +VANISHED+ response,
|
7
|
+
# which is described by the
|
8
|
+
# {QRESYNC}[https://www.rfc-editor.org/rfc/rfc7162.html] extension.
|
9
|
+
# [{RFC7162 §3.2.10}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.2.10]].
|
10
|
+
#
|
11
|
+
# +VANISHED+ responses replace +EXPUNGE+ responses when either the
|
12
|
+
# {QRESYNC}[https://www.rfc-editor.org/rfc/rfc7162.html] or the
|
13
|
+
# {UIDONLY}[https://www.rfc-editor.org/rfc/rfc9586.html] extension has been
|
14
|
+
# enabled.
|
15
|
+
class VanishedData < Data.define(:uids, :earlier)
|
16
|
+
|
17
|
+
# Returns a new VanishedData object.
|
18
|
+
#
|
19
|
+
# * +uids+ will be converted by SequenceSet.[].
|
20
|
+
# * +earlier+ will be converted to +true+ or +false+
|
21
|
+
def initialize(uids:, earlier:)
|
22
|
+
uids = SequenceSet[uids]
|
23
|
+
earlier = !!earlier
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# :attr_reader: uids
|
29
|
+
#
|
30
|
+
# SequenceSet of UIDs that have been permanently removed from the mailbox.
|
31
|
+
|
32
|
+
##
|
33
|
+
# :attr_reader: earlier
|
34
|
+
#
|
35
|
+
# +true+ when the response was caused by Net::IMAP#uid_fetch with
|
36
|
+
# <tt>vanished: true</tt> or Net::IMAP#select/Net::IMAP#examine with
|
37
|
+
# <tt>qresync: true</tt>.
|
38
|
+
#
|
39
|
+
# +false+ when the response is used to announce message removals within an
|
40
|
+
# already selected mailbox.
|
41
|
+
|
42
|
+
# rdoc doesn't handle attr aliases nicely. :(
|
43
|
+
alias earlier? earlier # :nodoc:
|
44
|
+
##
|
45
|
+
# :attr_reader: earlier?
|
46
|
+
#
|
47
|
+
# Alias for #earlier.
|
48
|
+
|
49
|
+
# Returns an Array of all of the UIDs in #uids.
|
50
|
+
#
|
51
|
+
# See SequenceSet#numbers.
|
52
|
+
def to_a; uids.numbers end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|