net-imap 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/docs/styles.css +0 -12
- data/lib/net/imap/data_encoding.rb +14 -2
- data/lib/net/imap/fetch_data.rb +518 -0
- data/lib/net/imap/response_data.rb +26 -207
- data/lib/net/imap/response_parser/parser_utils.rb +1 -1
- data/lib/net/imap/response_parser.rb +311 -58
- data/lib/net/imap/sequence_set.rb +67 -0
- data/lib/net/imap.rb +76 -17
- data/rakelib/benchmarks.rake +4 -11
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4e6a6afb6888a5be474a97195f41e06a2e1706d9f65a0700f17bce7f6dd82af
|
4
|
+
data.tar.gz: 3dd62a4e251d29e9e72e5538f548623662ed2ff16da46deadf8843585f8db658
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc73faf474cb22965f3ec95bdae48d13514505d4072f0fe3ca47f1dbccc8b04aad404e90ecd2b04afa7dc401dc2f66d087fea316b26e46edf1403945e7e3c305
|
7
|
+
data.tar.gz: 9c10a3b062c88f6145deb1adbbe3e8a2574e9f4dac39c2b7706fbc84643ee031891dae270197f910ceda3e5d0513f0929d574889e506c53a6f5048cb9be36dfa
|
data/.gitignore
CHANGED
data/docs/styles.css
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "date"
|
4
|
+
require "time"
|
4
5
|
|
5
6
|
require_relative "errors"
|
6
7
|
|
@@ -102,8 +103,16 @@ module Net
|
|
102
103
|
#
|
103
104
|
# Decodes +string+ as an IMAP4 formatted "date-time".
|
104
105
|
#
|
105
|
-
#
|
106
|
+
# NOTE: Although double-quotes are not optional in the IMAP grammar,
|
107
|
+
# Net::IMAP currently parses "date-time" values as "quoted" strings and this
|
108
|
+
# removes the quotation marks. To be useful for strings which have already
|
109
|
+
# been parsed as a quoted string, this method makes double-quotes optional.
|
110
|
+
#
|
111
|
+
# See STRFTIME.
|
106
112
|
def self.decode_datetime(string)
|
113
|
+
unless string.start_with?(?") && string.end_with?(?")
|
114
|
+
string = '"%s"' % [string]
|
115
|
+
end
|
107
116
|
DateTime.strptime(string, STRFTIME)
|
108
117
|
end
|
109
118
|
|
@@ -113,7 +122,10 @@ module Net
|
|
113
122
|
#
|
114
123
|
# Same as +decode_datetime+, but returning a Time instead.
|
115
124
|
def self.decode_time(string)
|
116
|
-
|
125
|
+
unless string.start_with?(?") && string.end_with?(?")
|
126
|
+
string = '"%s"' % [string]
|
127
|
+
end
|
128
|
+
Time.strptime(string, STRFTIME)
|
117
129
|
end
|
118
130
|
|
119
131
|
class << self
|
@@ -0,0 +1,518 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class IMAP < Protocol
|
5
|
+
|
6
|
+
# Net::IMAP::FetchData represents the contents of a FETCH response.
|
7
|
+
# Net::IMAP#fetch and Net::IMAP#uid_fetch both return an array of
|
8
|
+
# FetchData objects.
|
9
|
+
#
|
10
|
+
# === Fetch attributes
|
11
|
+
#
|
12
|
+
# See {[IMAP4rev1 §7.4.2]}[https://www.rfc-editor.org/rfc/rfc3501.html#section-7.4.2]
|
13
|
+
# and {[IMAP4rev2 §7.5.2]}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.5.2]
|
14
|
+
# for a full description of the standard fetch response data items, and
|
15
|
+
# Net::IMAP@Message+envelope+and+body+structure for other relevant RFCs.
|
16
|
+
#
|
17
|
+
# ==== Static fetch data items
|
18
|
+
#
|
19
|
+
# Most message attributes are static, and must never change for a given
|
20
|
+
# <tt>(server, account, mailbox, UIDVALIDITY, UID)</tt> tuple.
|
21
|
+
#
|
22
|
+
# The static fetch data items defined by both
|
23
|
+
# IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501.html] and
|
24
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html] are:
|
25
|
+
#
|
26
|
+
# * <b><tt>"UID"</tt></b> --- See #uid.
|
27
|
+
# * <b><tt>"BODY"</tt></b> --- See #body.
|
28
|
+
# * <b><tt>"BODY[#{section_spec}]"</tt></b>,
|
29
|
+
# <b><tt>"BODY[#{section_spec}]<#{offset}>"</tt></b> --- See #message,
|
30
|
+
# #part, #header, #header_fields, #header_fields_not, #mime, and #text.
|
31
|
+
# * <b><tt>"BODYSTRUCTURE"</tt></b> --- See #bodystructure.
|
32
|
+
# * <b><tt>"ENVELOPE"</tt></b> --- See #envelope.
|
33
|
+
# * <b><tt>"INTERNALDATE"</tt></b> --- See #internaldate.
|
34
|
+
# * <b><tt>"RFC822.SIZE"</tt></b> --- See #rfc822_size.
|
35
|
+
#
|
36
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html] adds the
|
37
|
+
# additional fetch items from the +BINARY+ extension
|
38
|
+
# {[RFC3516]}[https://www.rfc-editor.org/rfc/rfc3516.html]:
|
39
|
+
#
|
40
|
+
# * <b><tt>"BINARY[#{part}]"</tt></b>,
|
41
|
+
# <b><tt>"BINARY[#{part}]<#{offset}>"</tt></b> -- See #binary.
|
42
|
+
# * <b><tt>"BINARY.SIZE[#{part}]"</tt></b> -- See #binary_size.
|
43
|
+
#
|
44
|
+
# Several static message attributes in
|
45
|
+
# IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501.html] are obsolete and
|
46
|
+
# been removed from
|
47
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]:
|
48
|
+
#
|
49
|
+
# * <b><tt>"RFC822"</tt></b> --- See #rfc822 or replace with
|
50
|
+
# <tt>"BODY[]"</tt> and #message.
|
51
|
+
# * <b><tt>"RFC822.HEADER"</tt></b> --- See #rfc822_header or replace with
|
52
|
+
# <tt>"BODY[HEADER]"</tt> and #header.
|
53
|
+
# * <b><tt>"RFC822.TEXT"</tt></b> --- See #rfc822_text or replace with
|
54
|
+
# <tt>"BODY[TEXT]"</tt> and #text.
|
55
|
+
#
|
56
|
+
# Net::IMAP supports static attributes defined by the following extensions:
|
57
|
+
# * +OBJECTID+ {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html]
|
58
|
+
# * <b><tt>"EMAILID"</tt></b> --- See #emailid.
|
59
|
+
# * <b><tt>"THREADID"</tt></b> --- See #threadid.
|
60
|
+
#
|
61
|
+
# * +X-GM-EXT-1+ {[non-standard Gmail
|
62
|
+
# extension]}[https://developers.google.com/gmail/imap/imap-extensions]
|
63
|
+
# * <b><tt>"X-GM-MSGID"</tt></b> --- unique message ID. Access via #attr.
|
64
|
+
# * <b><tt>"X-GM-THRID"</tt></b> --- Thread ID. Access via #attr.
|
65
|
+
#
|
66
|
+
# [Note:]
|
67
|
+
# >>>
|
68
|
+
# Additional static fields are defined in other \IMAP extensions, but
|
69
|
+
# Net::IMAP can't parse them yet.
|
70
|
+
#
|
71
|
+
# ==== Dynamic message attributes
|
72
|
+
#
|
73
|
+
# Some message attributes can be dynamically changed, for example using the
|
74
|
+
# {STORE command}[rdoc-ref:Net::IMAP#store].
|
75
|
+
#
|
76
|
+
# The only dynamic message attribute defined by
|
77
|
+
# IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501.html] and
|
78
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html] is:
|
79
|
+
#
|
80
|
+
# * <b><tt>"FLAGS"</tt></b> --- See #flags.
|
81
|
+
#
|
82
|
+
# Net::IMAP supports dynamic attributes defined by the following extensions:
|
83
|
+
#
|
84
|
+
# * +CONDSTORE+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html]:
|
85
|
+
# * <b><tt>"MODSEQ"</tt></b> --- See #modseq.
|
86
|
+
# * +X-GM-EXT-1+ {[non-standard Gmail
|
87
|
+
# extension]}[https://developers.google.com/gmail/imap/imap-extensions]
|
88
|
+
# * <b><tt>"X-GM-LABELS"</tt></b> --- Gmail labels. Access via #attr.
|
89
|
+
#
|
90
|
+
# [Note:]
|
91
|
+
# >>>
|
92
|
+
# Additional dynamic fields are defined in other \IMAP extensions, but
|
93
|
+
# Net::IMAP can't parse them yet.
|
94
|
+
#
|
95
|
+
# === Implicitly setting <tt>\Seen</tt> and using +PEEK+
|
96
|
+
#
|
97
|
+
# Unless the mailbox is has been opened as read-only, fetching
|
98
|
+
# <tt>BODY[#{section}]</tt> or <tt>BINARY[#{section}]</tt>
|
99
|
+
# will implicitly set the <tt>\Seen</tt> flag. To avoid this, fetch using
|
100
|
+
# <tt>BODY.PEEK[#{section}]</tt> or <tt>BINARY.PEEK[#{section}]</tt>
|
101
|
+
# instead.
|
102
|
+
#
|
103
|
+
# Note that the data will always be _returned_ without <tt>".PEEK"</tt>, in
|
104
|
+
# <tt>BODY[#{specifier}]</tt> or <tt>BINARY[#{section}]</tt>.
|
105
|
+
#
|
106
|
+
class FetchData < Struct.new(:seqno, :attr)
|
107
|
+
##
|
108
|
+
# method: seqno
|
109
|
+
# :call-seq: seqno -> Integer
|
110
|
+
#
|
111
|
+
# The message sequence number.
|
112
|
+
#
|
113
|
+
# [Note]
|
114
|
+
# This is never the unique identifier (UID), not even for the
|
115
|
+
# Net::IMAP#uid_fetch result. The UID is available from #uid, if it was
|
116
|
+
# returned.
|
117
|
+
|
118
|
+
##
|
119
|
+
# method: attr
|
120
|
+
# :call-seq: attr -> hash
|
121
|
+
#
|
122
|
+
# Each key specifies a message attribute, and the value is the
|
123
|
+
# corresponding data item. Standard data items have corresponding
|
124
|
+
# accessor methods. The definitions of each attribute type is documented
|
125
|
+
# on its accessor.
|
126
|
+
#
|
127
|
+
# >>>
|
128
|
+
# *Note:* #seqno is not a message attribute.
|
129
|
+
|
130
|
+
# :call-seq: attr_upcase -> hash
|
131
|
+
#
|
132
|
+
# A transformation of #attr, with all the keys converted to upper case.
|
133
|
+
#
|
134
|
+
# Header field names are case-preserved but not not case-sensitive, so
|
135
|
+
# this is used by #header_fields and #header_fields_not.
|
136
|
+
def attr_upcase; attr.transform_keys(&:upcase) end
|
137
|
+
|
138
|
+
# :call-seq:
|
139
|
+
# body -> body structure or nil
|
140
|
+
#
|
141
|
+
# Returns an alternate form of #bodystructure, without any extension data.
|
142
|
+
#
|
143
|
+
# This is the same as getting the value for <tt>"BODY"</tt> from #attr.
|
144
|
+
#
|
145
|
+
# [Note]
|
146
|
+
# Use #message, #part, #header, #header_fields, #header_fields_not,
|
147
|
+
# #text, or #mime to retrieve <tt>BODY[#{section_spec}]</tt> attributes.
|
148
|
+
def body; attr["BODY"] end
|
149
|
+
|
150
|
+
# :call-seq:
|
151
|
+
# message(offset: bytes) -> string or nil
|
152
|
+
#
|
153
|
+
# The RFC5322[https://www.rfc-editor.org/rfc/rfc5322.html]
|
154
|
+
# expression of the entire message, as a string.
|
155
|
+
#
|
156
|
+
# See #part for a description of +offset+.
|
157
|
+
#
|
158
|
+
# <em>RFC5322 messages can be parsed using the "mail" gem.</em>
|
159
|
+
#
|
160
|
+
# This is the same as getting the value for <tt>"BODY[]"</tt> or
|
161
|
+
# <tt>"BODY[]<#{offset}>"</tt> from #attr.
|
162
|
+
#
|
163
|
+
# See also: #header, #text, and #mime.
|
164
|
+
def message(offset: nil) attr[body_section_attr(offset: offset)] end
|
165
|
+
|
166
|
+
# :call-seq:
|
167
|
+
# part(*part_nums, offset: bytes) -> string or nil
|
168
|
+
#
|
169
|
+
# The string representation of a particular MIME part.
|
170
|
+
#
|
171
|
+
# +part_nums+ forms a path of MIME part numbers, counting up from +1+,
|
172
|
+
# which may specify an arbitrarily nested part, similarly to Array#dig.
|
173
|
+
# Messages that don't use MIME, or MIME messages that are not multipart
|
174
|
+
# and don't hold an encapsulated message, only have part +1+.
|
175
|
+
#
|
176
|
+
# If a zero-based +offset+ is given, the returned string is a substring of
|
177
|
+
# the entire contents, starting at that origin octet. This means that
|
178
|
+
# <tt>BODY[]<0></tt> MAY be truncated, but <tt>BODY[]</tt> is never
|
179
|
+
# truncated.
|
180
|
+
#
|
181
|
+
# This is the same as getting the value of
|
182
|
+
# <tt>"BODY[#{part_nums.join(".")}]"</tt> or
|
183
|
+
# <tt>"BODY[#{part_nums.join(".")}]<#{offset}>"</tt> from #attr.
|
184
|
+
#
|
185
|
+
# See also: #message, #header, #text, and #mime.
|
186
|
+
def part(index, *subparts, offset: nil)
|
187
|
+
attr[body_section_attr([index, *subparts], offset: offset)]
|
188
|
+
end
|
189
|
+
|
190
|
+
# :call-seq:
|
191
|
+
# header(*part_nums, offset: nil) -> string or nil
|
192
|
+
# header(*part_nums, fields: names, offset: nil) -> string or nil
|
193
|
+
# header(*part_nums, except: names, offset: nil) -> string or nil
|
194
|
+
#
|
195
|
+
# The {[RFC5322]}[https://www.rfc-editor.org/rfc/rfc5322.html] header of a
|
196
|
+
# message or of an encapsulated
|
197
|
+
# {[MIME-IMT]}[https://www.rfc-editor.org/rfc/rfc2046.html]
|
198
|
+
# MESSAGE/RFC822 or MESSAGE/GLOBAL message.
|
199
|
+
#
|
200
|
+
# <em>Headers can be parsed using the "mail" gem.</em>
|
201
|
+
#
|
202
|
+
# See #part for a description of +part_nums+ and +offset+.
|
203
|
+
#
|
204
|
+
# ==== Without +fields+ or +except+
|
205
|
+
# This is the same as getting the value from #attr for one of:
|
206
|
+
# * <tt>BODY[HEADER]</tt>
|
207
|
+
# * <tt>BODY[HEADER]<#{offset}></tt>
|
208
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER]"</tt>
|
209
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER]<#{offset}>"</tt>
|
210
|
+
#
|
211
|
+
# ==== With +fields+
|
212
|
+
# When +fields+ is sent, returns a subset of the header which contains
|
213
|
+
# only the header fields that match one of the names in the list.
|
214
|
+
#
|
215
|
+
# This is the same as getting the value from #attr_upcase for one of:
|
216
|
+
# * <tt>BODY[HEADER.FIELDS (#{names.join " "})]</tt>
|
217
|
+
# * <tt>BODY[HEADER.FIELDS (#{names.join " "})]<#{offset}></tt>
|
218
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS (#{names.join " "})]</tt>
|
219
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS (#{names.join " "})]<#{offset}></tt>
|
220
|
+
#
|
221
|
+
# See also: #header_fields
|
222
|
+
#
|
223
|
+
# ==== With +except+
|
224
|
+
# When +except+ is sent, returns a subset of the header which contains
|
225
|
+
# only the header fields that do _not_ match one of the names in the list.
|
226
|
+
#
|
227
|
+
# This is the same as getting the value from #attr_upcase for one of:
|
228
|
+
# * <tt>BODY[HEADER.FIELDS.NOT (#{names.join " "})]</tt>
|
229
|
+
# * <tt>BODY[HEADER.FIELDS.NOT (#{names.join " "})]<#{offset}></tt>
|
230
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS.NOT (#{names.join " "})]</tt>
|
231
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS.NOT (#{names.join " "})]<#{offset}></tt>
|
232
|
+
#
|
233
|
+
# See also: #header_fields_not
|
234
|
+
def header(*part_nums, fields: nil, except: nil, offset: nil)
|
235
|
+
fields && except and
|
236
|
+
raise ArgumentError, "conflicting 'fields' and 'except' arguments"
|
237
|
+
if fields
|
238
|
+
text = "HEADER.FIELDS (%s)" % [fields.join(" ").upcase]
|
239
|
+
attr_upcase[body_section_attr(part_nums, text, offset: offset)]
|
240
|
+
elsif except
|
241
|
+
text = "HEADER.FIELDS.NOT (%s)" % [except.join(" ").upcase]
|
242
|
+
attr_upcase[body_section_attr(part_nums, text, offset: offset)]
|
243
|
+
else
|
244
|
+
attr[body_section_attr(part_nums, "HEADER", offset: offset)]
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# :call-seq:
|
249
|
+
# header_fields(*names, part: [], offset: nil) -> string or nil
|
250
|
+
#
|
251
|
+
# The result from #header when called with <tt>fields: names</tt>.
|
252
|
+
def header_fields(first, *rest, part: [], offset: nil)
|
253
|
+
header(*part, fields: [first, *rest], offset: offset)
|
254
|
+
end
|
255
|
+
|
256
|
+
# :call-seq:
|
257
|
+
# header_fields_not(*names, part: [], offset: nil) -> string or nil
|
258
|
+
#
|
259
|
+
# The result from #header when called with <tt>except: names</tt>.
|
260
|
+
def header_fields_not(first, *rest, part: [], offset: nil)
|
261
|
+
header(*part, except: [first, *rest], offset: offset)
|
262
|
+
end
|
263
|
+
|
264
|
+
# :call-seq:
|
265
|
+
# mime(*part_nums) -> string or nil
|
266
|
+
# mime(*part_nums, offset: bytes) -> string or nil
|
267
|
+
#
|
268
|
+
# The {[MIME-IMB]}[https://www.rfc-editor.org/rfc/rfc2045.html] header for
|
269
|
+
# a message part, if it was fetched.
|
270
|
+
#
|
271
|
+
# See #part for a description of +part_nums+ and +offset+.
|
272
|
+
#
|
273
|
+
# This is the same as getting the value for
|
274
|
+
# <tt>"BODY[#{part_nums}.MIME]"</tt> or
|
275
|
+
# <tt>"BODY[#{part_nums}.MIME]<#{offset}>"</tt> from #attr.
|
276
|
+
#
|
277
|
+
# See also: #message, #header, and #text.
|
278
|
+
def mime(part, *subparts, offset: nil)
|
279
|
+
attr[body_section_attr([part, *subparts], "MIME", offset: offset)]
|
280
|
+
end
|
281
|
+
|
282
|
+
# :call-seq:
|
283
|
+
# text(*part_nums) -> string or nil
|
284
|
+
# text(*part_nums, offset: bytes) -> string or nil
|
285
|
+
#
|
286
|
+
# The text body of a message or a message part, if it was fetched,
|
287
|
+
# omitting the {[RFC5322]}[https://www.rfc-editor.org/rfc/rfc5322.html]
|
288
|
+
# header.
|
289
|
+
#
|
290
|
+
# See #part for a description of +part_nums+ and +offset+.
|
291
|
+
#
|
292
|
+
# This is the same as getting the value from #attr for one of:
|
293
|
+
# * <tt>"BODY[TEXT]"</tt>,
|
294
|
+
# * <tt>"BODY[TEXT]<#{offset}>"</tt>,
|
295
|
+
# * <tt>"BODY[#{section}.TEXT]"</tt>, or
|
296
|
+
# * <tt>"BODY[#{section}.TEXT]<#{offset}>"</tt>.
|
297
|
+
#
|
298
|
+
# See also: #message, #header, and #mime.
|
299
|
+
def text(*part, offset: nil)
|
300
|
+
attr[body_section_attr(part, "TEXT", offset: offset)]
|
301
|
+
end
|
302
|
+
|
303
|
+
# :call-seq:
|
304
|
+
# bodystructure -> BodyStructure struct or nil
|
305
|
+
#
|
306
|
+
# A BodyStructure object that describes the message, if it was fetched.
|
307
|
+
#
|
308
|
+
# This is the same as getting the value for <tt>"BODYSTRUCTURE"</tt> from
|
309
|
+
# #attr.
|
310
|
+
def bodystructure; attr["BODYSTRUCTURE"] end
|
311
|
+
alias body_structure bodystructure
|
312
|
+
|
313
|
+
# :call-seq: envelope -> Envelope or nil
|
314
|
+
#
|
315
|
+
# An Envelope object that describes the envelope structure of a message.
|
316
|
+
# See the documentation for Envelope for a description of the envelope
|
317
|
+
# structure attributes.
|
318
|
+
#
|
319
|
+
# This is the same as getting the value for <tt>"ENVELOPE"</tt> from
|
320
|
+
# #attr.
|
321
|
+
def envelope; attr["ENVELOPE"] end
|
322
|
+
|
323
|
+
# :call-seq: flags -> array of Symbols and Strings
|
324
|
+
#
|
325
|
+
# A array of flags that are set for this message. System flags are
|
326
|
+
# symbols that have been capitalized by String#capitalize. Keyword flags
|
327
|
+
# are strings and their case is not changed.
|
328
|
+
#
|
329
|
+
# This is the same as getting the value for <tt>"FLAGS"</tt> from #attr.
|
330
|
+
#
|
331
|
+
# [Note]
|
332
|
+
# The +FLAGS+ field is dynamic, and can change for a uniquely identified
|
333
|
+
# message.
|
334
|
+
def flags; attr["FLAGS"] end
|
335
|
+
|
336
|
+
# :call-seq: internaldate -> Time or nil
|
337
|
+
#
|
338
|
+
# The internal date and time of the message on the server. This is not
|
339
|
+
# the date and time in the [RFC5322[https://tools.ietf.org/html/rfc5322]]
|
340
|
+
# header, but rather a date and time which reflects when the message was
|
341
|
+
# received.
|
342
|
+
#
|
343
|
+
# This is similar to getting the value for <tt>"INTERNALDATE"</tt> from
|
344
|
+
# #attr.
|
345
|
+
#
|
346
|
+
# [Note]
|
347
|
+
# <tt>attr["INTERNALDATE"]</tt> returns a string, and this method
|
348
|
+
# returns a Time object.
|
349
|
+
def internaldate
|
350
|
+
attr["INTERNALDATE"]&.then { IMAP.decode_time _1 }
|
351
|
+
end
|
352
|
+
alias internal_date internaldate
|
353
|
+
|
354
|
+
# :call-seq: rfc822 -> String
|
355
|
+
#
|
356
|
+
# Semantically equivalent to #message with no arguments.
|
357
|
+
#
|
358
|
+
# This is the same as getting the value for <tt>"RFC822"</tt> from #attr.
|
359
|
+
#
|
360
|
+
# [Note]
|
361
|
+
# +IMAP4rev2+ deprecates <tt>RFC822</tt>.
|
362
|
+
def rfc822; attr["RFC822"] end
|
363
|
+
|
364
|
+
# :call-seq: rfc822_size -> Integer
|
365
|
+
#
|
366
|
+
# A number expressing the [RFC5322[https://tools.ietf.org/html/rfc5322]]
|
367
|
+
# size of the message.
|
368
|
+
#
|
369
|
+
# This is the same as getting the value for <tt>"RFC822.SIZE"</tt> from
|
370
|
+
# #attr.
|
371
|
+
#
|
372
|
+
# [Note]
|
373
|
+
# \IMAP was originally developed for the older
|
374
|
+
# RFC822[https://www.rfc-editor.org/rfc/rfc822.html] standard, and as a
|
375
|
+
# consequence several fetch items in \IMAP incorporate "RFC822" in their
|
376
|
+
# name. With the exception of +RFC822.SIZE+, there are more modern
|
377
|
+
# replacements; for example, the modern version of +RFC822.HEADER+ is
|
378
|
+
# <tt>BODY.PEEK[HEADER]</tt>. In all cases, "RFC822" should be
|
379
|
+
# interpreted as a reference to the updated
|
380
|
+
# RFC5322[https://www.rfc-editor.org/rfc/rfc5322.html] standard.
|
381
|
+
def rfc822_size; attr["RFC822.SIZE"] end
|
382
|
+
alias size rfc822_size
|
383
|
+
|
384
|
+
# :call-seq: rfc822_header -> String
|
385
|
+
#
|
386
|
+
# Semantically equivalent to #header, with no arguments.
|
387
|
+
#
|
388
|
+
# This is the same as getting the value for <tt>"RFC822.HEADER"</tt> from #attr.
|
389
|
+
#
|
390
|
+
# [Note]
|
391
|
+
# +IMAP4rev2+ deprecates <tt>RFC822.HEADER</tt>.
|
392
|
+
def rfc822_header; attr["RFC822.HEADER"] end
|
393
|
+
|
394
|
+
# :call-seq: rfc822_text -> String
|
395
|
+
#
|
396
|
+
# Semantically equivalent to #text, with no arguments.
|
397
|
+
#
|
398
|
+
# This is the same as getting the value for <tt>"RFC822.TEXT"</tt> from
|
399
|
+
# #attr.
|
400
|
+
#
|
401
|
+
# [Note]
|
402
|
+
# +IMAP4rev2+ deprecates <tt>RFC822.TEXT</tt>.
|
403
|
+
def rfc822_text; attr["RFC822.TEXT"] end
|
404
|
+
|
405
|
+
# :call-seq: uid -> Integer
|
406
|
+
#
|
407
|
+
# A number expressing the unique identifier of the message.
|
408
|
+
#
|
409
|
+
# This is the same as getting the value for <tt>"UID"</tt> from #attr.
|
410
|
+
def uid; attr["UID"] end
|
411
|
+
|
412
|
+
# :call-seq:
|
413
|
+
# binary(*part_nums, offset: nil) -> string or nil
|
414
|
+
#
|
415
|
+
# Returns the binary representation of a particular MIME part, which has
|
416
|
+
# already been decoded according to its Content-Transfer-Encoding.
|
417
|
+
#
|
418
|
+
# See #part for a description of +part_nums+ and +offset+.
|
419
|
+
#
|
420
|
+
# This is the same as getting the value of
|
421
|
+
# <tt>"BINARY[#{part_nums.join(".")}]"</tt> or
|
422
|
+
# <tt>"BINARY[#{part_nums.join(".")}]<#{offset}>"</tt> from #attr.
|
423
|
+
#
|
424
|
+
# The server must support either
|
425
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]
|
426
|
+
# or the +BINARY+ extension
|
427
|
+
# {[RFC3516]}[https://www.rfc-editor.org/rfc/rfc3516.html].
|
428
|
+
#
|
429
|
+
# See also: #binary_size, #mime
|
430
|
+
def binary(*part_nums, offset: nil)
|
431
|
+
attr[section_attr("BINARY", part_nums, offset: offset)]
|
432
|
+
end
|
433
|
+
|
434
|
+
# :call-seq:
|
435
|
+
# binary_size(*part_nums) -> integer or nil
|
436
|
+
#
|
437
|
+
# Returns the decoded size of a particular MIME part (the size to expect
|
438
|
+
# in response to a <tt>BINARY</tt> fetch request).
|
439
|
+
#
|
440
|
+
# See #part for a description of +part_nums+.
|
441
|
+
#
|
442
|
+
# This is the same as getting the value of
|
443
|
+
# <tt>"BINARY.SIZE[#{part_nums.join(".")}]"</tt> from #attr.
|
444
|
+
#
|
445
|
+
# The server must support either
|
446
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]
|
447
|
+
# or the +BINARY+ extension
|
448
|
+
# {[RFC3516]}[https://www.rfc-editor.org/rfc/rfc3516.html].
|
449
|
+
#
|
450
|
+
# See also: #binary, #mime
|
451
|
+
def binary_size(*part_nums)
|
452
|
+
attr[section_attr("BINARY.SIZE", part_nums)]
|
453
|
+
end
|
454
|
+
|
455
|
+
# :call-seq: modseq -> Integer
|
456
|
+
#
|
457
|
+
# The modification sequence number associated with this IMAP message.
|
458
|
+
#
|
459
|
+
# This is the same as getting the value for <tt>"MODSEQ"</tt> from #attr.
|
460
|
+
#
|
461
|
+
# The server must support the +CONDSTORE+ extension
|
462
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
|
463
|
+
#
|
464
|
+
# [Note]
|
465
|
+
# The +MODSEQ+ field is dynamic, and can change for a uniquely
|
466
|
+
# identified message.
|
467
|
+
def modseq; attr["MODSEQ"] end
|
468
|
+
|
469
|
+
# :call-seq: emailid -> string or nil
|
470
|
+
#
|
471
|
+
# An ObjectID that uniquely identifies the immutable content of a single
|
472
|
+
# message.
|
473
|
+
#
|
474
|
+
# The server must return the same +EMAILID+ for both the source and
|
475
|
+
# destination messages after a COPY or MOVE command. However, it is
|
476
|
+
# possible for different messages with the same EMAILID to have different
|
477
|
+
# mutable attributes, such as flags.
|
478
|
+
#
|
479
|
+
# This is the same as getting the value for <tt>"EMAILID"</tt> from
|
480
|
+
# #attr.
|
481
|
+
#
|
482
|
+
# The server must support the +OBJECTID+ extension
|
483
|
+
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
|
484
|
+
def emailid; attr["EMAILID"] end
|
485
|
+
|
486
|
+
# :call-seq: threadid -> string or nil
|
487
|
+
#
|
488
|
+
# An ObjectID that uniquely identifies a set of messages that the server
|
489
|
+
# believes should be grouped together.
|
490
|
+
#
|
491
|
+
# It is generally based on some combination of References, In-Reply-To,
|
492
|
+
# and Subject, but the exact implementation is left up to the server
|
493
|
+
# implementation. The server should return the same thread identifier for
|
494
|
+
# related messages, even if they are in different mailboxes.
|
495
|
+
#
|
496
|
+
# This is the same as getting the value for <tt>"THREADID"</tt> from
|
497
|
+
# #attr.
|
498
|
+
#
|
499
|
+
# The server must support the +OBJECTID+ extension
|
500
|
+
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
|
501
|
+
def threadid; attr["THREADID"] end
|
502
|
+
|
503
|
+
private
|
504
|
+
|
505
|
+
def body_section_attr(...) section_attr("BODY", ...) end
|
506
|
+
|
507
|
+
def section_attr(attr, part = [], text = nil, offset: nil)
|
508
|
+
spec = Array(part).flatten.map { Integer(_1) }
|
509
|
+
spec << text if text
|
510
|
+
spec = spec.join(".")
|
511
|
+
if offset then "%s[%s]<%d>" % [attr, spec, Integer(offset)]
|
512
|
+
else "%s[%s]" % [attr, spec]
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|