net-imap 0.3.7 → 0.5.6
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.
- checksums.yaml +4 -4
- data/BSDL +22 -0
- data/COPYING +56 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +3 -22
- data/README.md +25 -8
- data/Rakefile +0 -7
- data/docs/styles.css +72 -23
- data/lib/net/imap/authenticators.rb +26 -57
- data/lib/net/imap/command_data.rb +74 -54
- data/lib/net/imap/config/attr_accessors.rb +75 -0
- data/lib/net/imap/config/attr_inheritance.rb +90 -0
- data/lib/net/imap/config/attr_type_coercion.rb +61 -0
- data/lib/net/imap/config.rb +470 -0
- data/lib/net/imap/data_encoding.rb +18 -6
- data/lib/net/imap/data_lite.rb +226 -0
- data/lib/net/imap/deprecated_client_options.rb +142 -0
- data/lib/net/imap/errors.rb +27 -1
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/fetch_data.rb +597 -0
- data/lib/net/imap/flags.rb +1 -1
- data/lib/net/imap/response_data.rb +250 -440
- data/lib/net/imap/response_parser/parser_utils.rb +245 -0
- data/lib/net/imap/response_parser.rb +1867 -1184
- data/lib/net/imap/sasl/anonymous_authenticator.rb +69 -0
- data/lib/net/imap/sasl/authentication_exchange.rb +139 -0
- data/lib/net/imap/sasl/authenticators.rb +122 -0
- data/lib/net/imap/sasl/client_adapter.rb +123 -0
- data/lib/net/imap/{authenticators/cram_md5.rb → sasl/cram_md5_authenticator.rb} +24 -14
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +342 -0
- data/lib/net/imap/sasl/external_authenticator.rb +83 -0
- data/lib/net/imap/sasl/gs2_header.rb +80 -0
- data/lib/net/imap/{authenticators/login.rb → sasl/login_authenticator.rb} +28 -18
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +199 -0
- data/lib/net/imap/sasl/plain_authenticator.rb +101 -0
- data/lib/net/imap/sasl/protocol_adapters.rb +101 -0
- data/lib/net/imap/sasl/scram_algorithm.rb +58 -0
- data/lib/net/imap/sasl/scram_authenticator.rb +287 -0
- data/lib/net/imap/sasl/stringprep.rb +6 -66
- data/lib/net/imap/sasl/xoauth2_authenticator.rb +106 -0
- data/lib/net/imap/sasl.rb +148 -44
- data/lib/net/imap/sasl_adapter.rb +20 -0
- data/lib/net/imap/search_result.rb +146 -0
- data/lib/net/imap/sequence_set.rb +1565 -0
- data/lib/net/imap/stringprep/nameprep.rb +70 -0
- data/lib/net/imap/stringprep/saslprep.rb +69 -0
- data/lib/net/imap/stringprep/saslprep_tables.rb +96 -0
- data/lib/net/imap/stringprep/tables.rb +146 -0
- data/lib/net/imap/stringprep/trace.rb +85 -0
- data/lib/net/imap/stringprep.rb +159 -0
- data/lib/net/imap/uidplus_data.rb +244 -0
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +2090 -823
- data/net-imap.gemspec +7 -8
- data/rakelib/benchmarks.rake +91 -0
- data/rakelib/rfcs.rake +2 -0
- data/rakelib/saslprep.rake +4 -4
- data/rakelib/string_prep_tables_generator.rb +84 -60
- data/sample/net-imap.rb +167 -0
- metadata +45 -49
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/test.yml +0 -38
- data/.gitignore +0 -10
- data/benchmarks/stringprep.yml +0 -65
- data/benchmarks/table-regexps.yml +0 -39
- data/lib/net/imap/authenticators/digest_md5.rb +0 -115
- data/lib/net/imap/authenticators/plain.rb +0 -41
- data/lib/net/imap/authenticators/xoauth2.rb +0 -20
- data/lib/net/imap/sasl/saslprep.rb +0 -55
- data/lib/net/imap/sasl/saslprep_tables.rb +0 -98
- data/lib/net/imap/sasl/stringprep_tables.rb +0 -153
@@ -0,0 +1,597 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class IMAP < Protocol
|
5
|
+
|
6
|
+
# Net::IMAP::FetchStruct is the superclass for FetchData and UIDFetchData.
|
7
|
+
# Net::IMAP#fetch, Net::IMAP#uid_fetch, Net::IMAP#store, and
|
8
|
+
# Net::IMAP#uid_store all return arrays of FetchStruct 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
|
+
# Additional static fields are defined in other \IMAP extensions, but
|
68
|
+
# Net::IMAP can't parse them yet.
|
69
|
+
#
|
70
|
+
# ==== Dynamic message attributes
|
71
|
+
#
|
72
|
+
# Some message attributes can be dynamically changed, for example using the
|
73
|
+
# {STORE command}[rdoc-ref:Net::IMAP#store].
|
74
|
+
#
|
75
|
+
# The only dynamic message attribute defined by
|
76
|
+
# IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501.html] and
|
77
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html] is:
|
78
|
+
#
|
79
|
+
# * <b><tt>"FLAGS"</tt></b> --- See #flags.
|
80
|
+
#
|
81
|
+
# Net::IMAP supports dynamic attributes defined by the following extensions:
|
82
|
+
#
|
83
|
+
# * +CONDSTORE+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html]:
|
84
|
+
# * <b><tt>"MODSEQ"</tt></b> --- See #modseq.
|
85
|
+
# * +X-GM-EXT-1+ {[non-standard Gmail
|
86
|
+
# extension]}[https://developers.google.com/gmail/imap/imap-extensions]
|
87
|
+
# * <b><tt>"X-GM-LABELS"</tt></b> --- Gmail labels. Access via #attr.
|
88
|
+
#
|
89
|
+
# [NOTE:]
|
90
|
+
# Additional dynamic fields are defined in other \IMAP extensions, but
|
91
|
+
# Net::IMAP can't parse them yet.
|
92
|
+
#
|
93
|
+
# === Implicitly setting <tt>\Seen</tt> and using +PEEK+
|
94
|
+
#
|
95
|
+
# Unless the mailbox has been opened as read-only, fetching
|
96
|
+
# <tt>BODY[#{section}]</tt> or <tt>BINARY[#{section}]</tt>
|
97
|
+
# will implicitly set the <tt>\Seen</tt> flag. To avoid this, fetch using
|
98
|
+
# <tt>BODY.PEEK[#{section}]</tt> or <tt>BINARY.PEEK[#{section}]</tt>
|
99
|
+
# instead.
|
100
|
+
#
|
101
|
+
# [NOTE:]
|
102
|
+
# The data will always be _returned_ without the <tt>".PEEK"</tt> suffix,
|
103
|
+
# as <tt>BODY[#{specifier}]</tt> or <tt>BINARY[#{section}]</tt>.
|
104
|
+
#
|
105
|
+
class FetchStruct < Struct
|
106
|
+
##
|
107
|
+
# method: attr
|
108
|
+
# :call-seq: attr -> hash
|
109
|
+
#
|
110
|
+
# Each key specifies a message attribute, and the value is the
|
111
|
+
# corresponding data item. Standard data items have corresponding
|
112
|
+
# accessor methods. The definitions of each attribute type is documented
|
113
|
+
# on its accessor.
|
114
|
+
|
115
|
+
# :call-seq: attr_upcase -> hash
|
116
|
+
#
|
117
|
+
# A transformation of #attr, with all the keys converted to upper case.
|
118
|
+
#
|
119
|
+
# Header field names are case-preserved but not case-sensitive, so this is
|
120
|
+
# used by #header_fields and #header_fields_not.
|
121
|
+
def attr_upcase; attr.transform_keys(&:upcase) end
|
122
|
+
|
123
|
+
# :call-seq:
|
124
|
+
# body -> body structure or nil
|
125
|
+
#
|
126
|
+
# Returns an alternate form of #bodystructure, without any extension data.
|
127
|
+
#
|
128
|
+
# This is the same as getting the value for <tt>"BODY"</tt> from #attr.
|
129
|
+
#
|
130
|
+
# [NOTE:]
|
131
|
+
# Use #message, #part, #header, #header_fields, #header_fields_not,
|
132
|
+
# #text, or #mime to retrieve <tt>BODY[#{section_spec}]</tt> attributes.
|
133
|
+
def body; attr["BODY"] end
|
134
|
+
|
135
|
+
# :call-seq:
|
136
|
+
# message(offset: bytes) -> string or nil
|
137
|
+
#
|
138
|
+
# The RFC5322[https://www.rfc-editor.org/rfc/rfc5322.html]
|
139
|
+
# expression of the entire message, as a string.
|
140
|
+
#
|
141
|
+
# See #part for a description of +offset+.
|
142
|
+
#
|
143
|
+
# <em>RFC5322 messages can be parsed using the "mail" gem.</em>
|
144
|
+
#
|
145
|
+
# This is the same as getting the value for <tt>"BODY[]"</tt> or
|
146
|
+
# <tt>"BODY[]<#{offset}>"</tt> from #attr.
|
147
|
+
#
|
148
|
+
# See also: #header, #text, and #mime.
|
149
|
+
def message(offset: nil) attr[body_section_attr(offset: offset)] end
|
150
|
+
|
151
|
+
# :call-seq:
|
152
|
+
# part(*part_nums, offset: bytes) -> string or nil
|
153
|
+
#
|
154
|
+
# The string representation of a particular MIME part.
|
155
|
+
#
|
156
|
+
# +part_nums+ forms a path of MIME part numbers, counting up from +1+,
|
157
|
+
# which may specify an arbitrarily nested part, similarly to Array#dig.
|
158
|
+
# Messages that don't use MIME, or MIME messages that are not multipart
|
159
|
+
# and don't hold an encapsulated message, only have part +1+.
|
160
|
+
#
|
161
|
+
# If a zero-based +offset+ is given, the returned string is a substring of
|
162
|
+
# the entire contents, starting at that origin octet. This means that
|
163
|
+
# <tt>BODY[]<0></tt> MAY be truncated, but <tt>BODY[]</tt> is never
|
164
|
+
# truncated.
|
165
|
+
#
|
166
|
+
# This is the same as getting the value of
|
167
|
+
# <tt>"BODY[#{part_nums.join(".")}]"</tt> or
|
168
|
+
# <tt>"BODY[#{part_nums.join(".")}]<#{offset}>"</tt> from #attr.
|
169
|
+
#
|
170
|
+
# See also: #message, #header, #text, and #mime.
|
171
|
+
def part(index, *subparts, offset: nil)
|
172
|
+
attr[body_section_attr([index, *subparts], offset: offset)]
|
173
|
+
end
|
174
|
+
|
175
|
+
# :call-seq:
|
176
|
+
# header(*part_nums, offset: nil) -> string or nil
|
177
|
+
# header(*part_nums, fields: names, offset: nil) -> string or nil
|
178
|
+
# header(*part_nums, except: names, offset: nil) -> string or nil
|
179
|
+
#
|
180
|
+
# The {[RFC5322]}[https://www.rfc-editor.org/rfc/rfc5322.html] header of a
|
181
|
+
# message or of an encapsulated
|
182
|
+
# {[MIME-IMT]}[https://www.rfc-editor.org/rfc/rfc2046.html]
|
183
|
+
# MESSAGE/RFC822 or MESSAGE/GLOBAL message.
|
184
|
+
#
|
185
|
+
# <em>Headers can be parsed using the "mail" gem.</em>
|
186
|
+
#
|
187
|
+
# See #part for a description of +part_nums+ and +offset+.
|
188
|
+
#
|
189
|
+
# ==== Without +fields+ or +except+
|
190
|
+
# This is the same as getting the value from #attr for one of:
|
191
|
+
# * <tt>BODY[HEADER]</tt>
|
192
|
+
# * <tt>BODY[HEADER]<#{offset}></tt>
|
193
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER]"</tt>
|
194
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER]<#{offset}>"</tt>
|
195
|
+
#
|
196
|
+
# ==== With +fields+
|
197
|
+
# When +fields+ is sent, returns a subset of the header which contains
|
198
|
+
# only the header fields that match one of the names in the list.
|
199
|
+
#
|
200
|
+
# This is the same as getting the value from #attr_upcase for one of:
|
201
|
+
# * <tt>BODY[HEADER.FIELDS (#{names.join " "})]</tt>
|
202
|
+
# * <tt>BODY[HEADER.FIELDS (#{names.join " "})]<#{offset}></tt>
|
203
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS (#{names.join " "})]</tt>
|
204
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS (#{names.join " "})]<#{offset}></tt>
|
205
|
+
#
|
206
|
+
# See also: #header_fields
|
207
|
+
#
|
208
|
+
# ==== With +except+
|
209
|
+
# When +except+ is sent, returns a subset of the header which contains
|
210
|
+
# only the header fields that do _not_ match one of the names in the list.
|
211
|
+
#
|
212
|
+
# This is the same as getting the value from #attr_upcase for one of:
|
213
|
+
# * <tt>BODY[HEADER.FIELDS.NOT (#{names.join " "})]</tt>
|
214
|
+
# * <tt>BODY[HEADER.FIELDS.NOT (#{names.join " "})]<#{offset}></tt>
|
215
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS.NOT (#{names.join " "})]</tt>
|
216
|
+
# * <tt>BODY[#{part_nums.join "."}.HEADER.FIELDS.NOT (#{names.join " "})]<#{offset}></tt>
|
217
|
+
#
|
218
|
+
# See also: #header_fields_not
|
219
|
+
def header(*part_nums, fields: nil, except: nil, offset: nil)
|
220
|
+
fields && except and
|
221
|
+
raise ArgumentError, "conflicting 'fields' and 'except' arguments"
|
222
|
+
if fields
|
223
|
+
text = "HEADER.FIELDS (%s)" % [fields.join(" ").upcase]
|
224
|
+
attr_upcase[body_section_attr(part_nums, text, offset: offset)]
|
225
|
+
elsif except
|
226
|
+
text = "HEADER.FIELDS.NOT (%s)" % [except.join(" ").upcase]
|
227
|
+
attr_upcase[body_section_attr(part_nums, text, offset: offset)]
|
228
|
+
else
|
229
|
+
attr[body_section_attr(part_nums, "HEADER", offset: offset)]
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# :call-seq:
|
234
|
+
# header_fields(*names, part: [], offset: nil) -> string or nil
|
235
|
+
#
|
236
|
+
# The result from #header when called with <tt>fields: names</tt>.
|
237
|
+
def header_fields(first, *rest, part: [], offset: nil)
|
238
|
+
header(*part, fields: [first, *rest], offset: offset)
|
239
|
+
end
|
240
|
+
|
241
|
+
# :call-seq:
|
242
|
+
# header_fields_not(*names, part: [], offset: nil) -> string or nil
|
243
|
+
#
|
244
|
+
# The result from #header when called with <tt>except: names</tt>.
|
245
|
+
def header_fields_not(first, *rest, part: [], offset: nil)
|
246
|
+
header(*part, except: [first, *rest], offset: offset)
|
247
|
+
end
|
248
|
+
|
249
|
+
# :call-seq:
|
250
|
+
# mime(*part_nums) -> string or nil
|
251
|
+
# mime(*part_nums, offset: bytes) -> string or nil
|
252
|
+
#
|
253
|
+
# The {[MIME-IMB]}[https://www.rfc-editor.org/rfc/rfc2045.html] header for
|
254
|
+
# a message part, if it was fetched.
|
255
|
+
#
|
256
|
+
# See #part for a description of +part_nums+ and +offset+.
|
257
|
+
#
|
258
|
+
# This is the same as getting the value for
|
259
|
+
# <tt>"BODY[#{part_nums}.MIME]"</tt> or
|
260
|
+
# <tt>"BODY[#{part_nums}.MIME]<#{offset}>"</tt> from #attr.
|
261
|
+
#
|
262
|
+
# See also: #message, #header, and #text.
|
263
|
+
def mime(part, *subparts, offset: nil)
|
264
|
+
attr[body_section_attr([part, *subparts], "MIME", offset: offset)]
|
265
|
+
end
|
266
|
+
|
267
|
+
# :call-seq:
|
268
|
+
# text(*part_nums) -> string or nil
|
269
|
+
# text(*part_nums, offset: bytes) -> string or nil
|
270
|
+
#
|
271
|
+
# The text body of a message or a message part, if it was fetched,
|
272
|
+
# omitting the {[RFC5322]}[https://www.rfc-editor.org/rfc/rfc5322.html]
|
273
|
+
# header.
|
274
|
+
#
|
275
|
+
# See #part for a description of +part_nums+ and +offset+.
|
276
|
+
#
|
277
|
+
# This is the same as getting the value from #attr for one of:
|
278
|
+
# * <tt>"BODY[TEXT]"</tt>,
|
279
|
+
# * <tt>"BODY[TEXT]<#{offset}>"</tt>,
|
280
|
+
# * <tt>"BODY[#{section}.TEXT]"</tt>, or
|
281
|
+
# * <tt>"BODY[#{section}.TEXT]<#{offset}>"</tt>.
|
282
|
+
#
|
283
|
+
# See also: #message, #header, and #mime.
|
284
|
+
def text(*part, offset: nil)
|
285
|
+
attr[body_section_attr(part, "TEXT", offset: offset)]
|
286
|
+
end
|
287
|
+
|
288
|
+
# :call-seq:
|
289
|
+
# bodystructure -> BodyStructure struct or nil
|
290
|
+
#
|
291
|
+
# A BodyStructure object that describes the message, if it was fetched.
|
292
|
+
#
|
293
|
+
# This is the same as getting the value for <tt>"BODYSTRUCTURE"</tt> from
|
294
|
+
# #attr.
|
295
|
+
def bodystructure; attr["BODYSTRUCTURE"] end
|
296
|
+
|
297
|
+
alias body_structure bodystructure
|
298
|
+
|
299
|
+
# :call-seq: envelope -> Envelope or nil
|
300
|
+
#
|
301
|
+
# An Envelope object that describes the envelope structure of a message.
|
302
|
+
# See the documentation for Envelope for a description of the envelope
|
303
|
+
# structure attributes.
|
304
|
+
#
|
305
|
+
# This is the same as getting the value for <tt>"ENVELOPE"</tt> from
|
306
|
+
# #attr.
|
307
|
+
def envelope; attr["ENVELOPE"] end
|
308
|
+
|
309
|
+
# :call-seq: flags -> array of Symbols and Strings, or nil
|
310
|
+
#
|
311
|
+
# A array of flags that are set for this message. System flags are
|
312
|
+
# symbols that have been capitalized by String#capitalize. Keyword flags
|
313
|
+
# are strings and their case is not changed.
|
314
|
+
#
|
315
|
+
# This is the same as getting the value for <tt>"FLAGS"</tt> from #attr.
|
316
|
+
#
|
317
|
+
# [NOTE:]
|
318
|
+
# The +FLAGS+ field is dynamic, and can change for a uniquely identified
|
319
|
+
# message.
|
320
|
+
def flags; attr["FLAGS"] end
|
321
|
+
|
322
|
+
# :call-seq: internaldate -> Time or nil
|
323
|
+
#
|
324
|
+
# The internal date and time of the message on the server. This is not
|
325
|
+
# the date and time in the [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]
|
326
|
+
# header, but rather a date and time which reflects when the message was
|
327
|
+
# received.
|
328
|
+
#
|
329
|
+
# This is similar to getting the value for <tt>"INTERNALDATE"</tt> from
|
330
|
+
# #attr.
|
331
|
+
#
|
332
|
+
# [NOTE:]
|
333
|
+
# <tt>attr["INTERNALDATE"]</tt> returns a string, and this method
|
334
|
+
# returns a Time object.
|
335
|
+
def internaldate
|
336
|
+
attr["INTERNALDATE"]&.then { IMAP.decode_time _1 }
|
337
|
+
end
|
338
|
+
|
339
|
+
alias internal_date internaldate
|
340
|
+
|
341
|
+
# :call-seq: rfc822 -> String or nil
|
342
|
+
#
|
343
|
+
# Semantically equivalent to #message with no arguments.
|
344
|
+
#
|
345
|
+
# This is the same as getting the value for <tt>"RFC822"</tt> from #attr.
|
346
|
+
#
|
347
|
+
# [NOTE:]
|
348
|
+
# +IMAP4rev2+ deprecates <tt>RFC822</tt>.
|
349
|
+
def rfc822; attr["RFC822"] end
|
350
|
+
|
351
|
+
# :call-seq: rfc822_size -> Integer or nil
|
352
|
+
#
|
353
|
+
# A number expressing the [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]
|
354
|
+
# size of the message.
|
355
|
+
#
|
356
|
+
# This is the same as getting the value for <tt>"RFC822.SIZE"</tt> from
|
357
|
+
# #attr.
|
358
|
+
#
|
359
|
+
# [NOTE:]
|
360
|
+
# \IMAP was originally developed for the older
|
361
|
+
# RFC822[https://www.rfc-editor.org/rfc/rfc822.html] standard, and as a
|
362
|
+
# consequence several fetch items in \IMAP incorporate "RFC822" in their
|
363
|
+
# name. With the exception of +RFC822.SIZE+, there are more modern
|
364
|
+
# replacements; for example, the modern version of +RFC822.HEADER+ is
|
365
|
+
# <tt>BODY.PEEK[HEADER]</tt>. In all cases, "RFC822" should be
|
366
|
+
# interpreted as a reference to the updated
|
367
|
+
# RFC5322[https://www.rfc-editor.org/rfc/rfc5322.html] standard.
|
368
|
+
def rfc822_size; attr["RFC822.SIZE"] end
|
369
|
+
|
370
|
+
# NOTE: a bug in rdoc 6.7 prevents us from adding a call-seq to
|
371
|
+
# rfc822_size _and_ aliasing size => rfc822_size. Is it because this
|
372
|
+
# class inherits from Struct?
|
373
|
+
|
374
|
+
# Alias for: rfc822_size
|
375
|
+
def size; rfc822_size end
|
376
|
+
|
377
|
+
|
378
|
+
# :call-seq: rfc822_header -> String or nil
|
379
|
+
#
|
380
|
+
# Semantically equivalent to #header, with no arguments.
|
381
|
+
#
|
382
|
+
# This is the same as getting the value for <tt>"RFC822.HEADER"</tt> from #attr.
|
383
|
+
#
|
384
|
+
# [NOTE:]
|
385
|
+
# +IMAP4rev2+ deprecates <tt>RFC822.HEADER</tt>.
|
386
|
+
def rfc822_header; attr["RFC822.HEADER"] end
|
387
|
+
|
388
|
+
# :call-seq: rfc822_text -> String or nil
|
389
|
+
#
|
390
|
+
# Semantically equivalent to #text, with no arguments.
|
391
|
+
#
|
392
|
+
# This is the same as getting the value for <tt>"RFC822.TEXT"</tt> from
|
393
|
+
# #attr.
|
394
|
+
#
|
395
|
+
# [NOTE:]
|
396
|
+
# +IMAP4rev2+ deprecates <tt>RFC822.TEXT</tt>.
|
397
|
+
def rfc822_text; attr["RFC822.TEXT"] end
|
398
|
+
|
399
|
+
# :call-seq: uid -> Integer or nil
|
400
|
+
#
|
401
|
+
# A number expressing the unique identifier of the message.
|
402
|
+
#
|
403
|
+
# This is the same as getting the value for <tt>"UID"</tt> from #attr.
|
404
|
+
#
|
405
|
+
# [NOTE:]
|
406
|
+
# For UIDFetchData, this returns the uniqueid at the beginning of the
|
407
|
+
# +UIDFETCH+ response, _not_ the value from #attr.
|
408
|
+
def uid; attr["UID"] end
|
409
|
+
|
410
|
+
# :call-seq:
|
411
|
+
# binary(*part_nums, offset: nil) -> string or nil
|
412
|
+
#
|
413
|
+
# Returns the binary representation of a particular MIME part, which has
|
414
|
+
# already been decoded according to its Content-Transfer-Encoding.
|
415
|
+
#
|
416
|
+
# See #part for a description of +part_nums+ and +offset+.
|
417
|
+
#
|
418
|
+
# This is the same as getting the value of
|
419
|
+
# <tt>"BINARY[#{part_nums.join(".")}]"</tt> or
|
420
|
+
# <tt>"BINARY[#{part_nums.join(".")}]<#{offset}>"</tt> from #attr.
|
421
|
+
#
|
422
|
+
# The server must support either
|
423
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]
|
424
|
+
# or the +BINARY+ extension
|
425
|
+
# {[RFC3516]}[https://www.rfc-editor.org/rfc/rfc3516.html].
|
426
|
+
#
|
427
|
+
# See also: #binary_size, #mime
|
428
|
+
def binary(*part_nums, offset: nil)
|
429
|
+
attr[section_attr("BINARY", part_nums, offset: offset)]
|
430
|
+
end
|
431
|
+
|
432
|
+
# :call-seq:
|
433
|
+
# binary_size(*part_nums) -> integer or nil
|
434
|
+
#
|
435
|
+
# Returns the decoded size of a particular MIME part (the size to expect
|
436
|
+
# in response to a <tt>BINARY</tt> fetch request).
|
437
|
+
#
|
438
|
+
# See #part for a description of +part_nums+.
|
439
|
+
#
|
440
|
+
# This is the same as getting the value of
|
441
|
+
# <tt>"BINARY.SIZE[#{part_nums.join(".")}]"</tt> from #attr.
|
442
|
+
#
|
443
|
+
# The server must support either
|
444
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]
|
445
|
+
# or the +BINARY+ extension
|
446
|
+
# {[RFC3516]}[https://www.rfc-editor.org/rfc/rfc3516.html].
|
447
|
+
#
|
448
|
+
# See also: #binary, #mime
|
449
|
+
def binary_size(*part_nums)
|
450
|
+
attr[section_attr("BINARY.SIZE", part_nums)]
|
451
|
+
end
|
452
|
+
|
453
|
+
# :call-seq: modseq -> Integer or nil
|
454
|
+
#
|
455
|
+
# The modification sequence number associated with this IMAP message.
|
456
|
+
#
|
457
|
+
# This is the same as getting the value for <tt>"MODSEQ"</tt> from #attr.
|
458
|
+
#
|
459
|
+
# The server must support the +CONDSTORE+ extension
|
460
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
|
461
|
+
#
|
462
|
+
# [NOTE:]
|
463
|
+
# The +MODSEQ+ field is dynamic, and can change for a uniquely
|
464
|
+
# identified message.
|
465
|
+
def modseq; attr["MODSEQ"] end
|
466
|
+
|
467
|
+
# :call-seq: emailid -> string or nil
|
468
|
+
#
|
469
|
+
# An ObjectID that uniquely identifies the immutable content of a single
|
470
|
+
# message.
|
471
|
+
#
|
472
|
+
# The server must return the same +EMAILID+ for both the source and
|
473
|
+
# destination messages after a COPY or MOVE command. However, it is
|
474
|
+
# possible for different messages with the same EMAILID to have different
|
475
|
+
# mutable attributes, such as flags.
|
476
|
+
#
|
477
|
+
# This is the same as getting the value for <tt>"EMAILID"</tt> from
|
478
|
+
# #attr.
|
479
|
+
#
|
480
|
+
# The server must support the +OBJECTID+ extension
|
481
|
+
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
|
482
|
+
def emailid; attr["EMAILID"] end
|
483
|
+
|
484
|
+
# :call-seq: threadid -> string or nil
|
485
|
+
#
|
486
|
+
# An ObjectID that uniquely identifies a set of messages that the server
|
487
|
+
# believes should be grouped together.
|
488
|
+
#
|
489
|
+
# It is generally based on some combination of References, In-Reply-To,
|
490
|
+
# and Subject, but the exact implementation is left up to the server
|
491
|
+
# implementation. The server should return the same thread identifier for
|
492
|
+
# related messages, even if they are in different mailboxes.
|
493
|
+
#
|
494
|
+
# This is the same as getting the value for <tt>"THREADID"</tt> from
|
495
|
+
# #attr.
|
496
|
+
#
|
497
|
+
# The server must support the +OBJECTID+ extension
|
498
|
+
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
|
499
|
+
def threadid; attr["THREADID"] end
|
500
|
+
|
501
|
+
private
|
502
|
+
|
503
|
+
def body_section_attr(...) section_attr("BODY", ...) end
|
504
|
+
|
505
|
+
def section_attr(attr, part = [], text = nil, offset: nil)
|
506
|
+
spec = Array(part).flatten.map { Integer(_1) }
|
507
|
+
spec << text if text
|
508
|
+
spec = spec.join(".")
|
509
|
+
if offset then "%s[%s]<%d>" % [attr, spec, Integer(offset)] else "%s[%s]" % [attr, spec] end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
# Net::IMAP::FetchData represents the contents of a +FETCH+ response.
|
514
|
+
# Net::IMAP#fetch, Net::IMAP#uid_fetch, Net::IMAP#store, and
|
515
|
+
# Net::IMAP#uid_store all return arrays of FetchData objects, except when
|
516
|
+
# the +UIDONLY+ extension is enabled.
|
517
|
+
#
|
518
|
+
# See FetchStruct documentation for a list of standard message attributes.
|
519
|
+
class FetchData < FetchStruct.new(:seqno, :attr)
|
520
|
+
##
|
521
|
+
# method: seqno
|
522
|
+
# :call-seq: seqno -> Integer
|
523
|
+
#
|
524
|
+
# The message sequence number.
|
525
|
+
#
|
526
|
+
# [NOTE:]
|
527
|
+
# This is not the same as the unique identifier (UID), not even for the
|
528
|
+
# Net::IMAP#uid_fetch result. The UID is available from #uid, if it was
|
529
|
+
# returned.
|
530
|
+
#
|
531
|
+
# [NOTE:]
|
532
|
+
# UIDFetchData will raise a NoMethodError.
|
533
|
+
|
534
|
+
##
|
535
|
+
# method: attr
|
536
|
+
# :call-seq: attr -> hash
|
537
|
+
#
|
538
|
+
# Each key specifies a message attribute, and the value is the
|
539
|
+
# corresponding data item. Standard data items have corresponding
|
540
|
+
# accessor methods. The definitions of each attribute type is documented
|
541
|
+
# on its accessor.
|
542
|
+
#
|
543
|
+
# See FetchStruct documentation for message attribute accessors.
|
544
|
+
#
|
545
|
+
# [NOTE:]
|
546
|
+
# #seqno is not a message attribute.
|
547
|
+
end
|
548
|
+
|
549
|
+
# Net::IMAP::UIDFetchData represents the contents of a +UIDFETCH+ response,
|
550
|
+
# When the +UIDONLY+ extension has been enabled, Net::IMAP#uid_fetch and
|
551
|
+
# Net::IMAP#uid_store will both return an array of UIDFetchData objects.
|
552
|
+
#
|
553
|
+
# UIDFetchData contains the same message attributes as FetchData. However,
|
554
|
+
# +UIDFETCH+ responses return the UID at the beginning of the response,
|
555
|
+
# replacing FetchData#seqno. UIDFetchData never contains a message sequence
|
556
|
+
# number.
|
557
|
+
#
|
558
|
+
# See FetchStruct documentation for a list of standard message attributes.
|
559
|
+
class UIDFetchData < FetchStruct.new(:uid, :attr)
|
560
|
+
##
|
561
|
+
# method: uid
|
562
|
+
# call-seq: uid -> Integer
|
563
|
+
#
|
564
|
+
# A number expressing the unique identifier of the message.
|
565
|
+
#
|
566
|
+
# [NOTE:]
|
567
|
+
# Although #attr may _also_ have a redundant +UID+ attribute, #uid
|
568
|
+
# returns the uniqueid at the beginning of the +UIDFETCH+ response.
|
569
|
+
|
570
|
+
##
|
571
|
+
# method: attr
|
572
|
+
# call-seq: attr -> hash
|
573
|
+
#
|
574
|
+
# Each key specifies a message attribute, and the value is the
|
575
|
+
# corresponding data item. Standard data items have corresponding
|
576
|
+
# accessor methods. The definitions of each attribute type is documented
|
577
|
+
# on its accessor.
|
578
|
+
#
|
579
|
+
# See FetchStruct documentation for message attribute accessors.
|
580
|
+
#
|
581
|
+
# [NOTE:]
|
582
|
+
# #uid is not a message attribute. Although the server may return a
|
583
|
+
# +UID+ message attribute, it is not required to. #uid is taken from
|
584
|
+
# its corresponding +UIDFETCH+ field.
|
585
|
+
|
586
|
+
# UIDFetchData will print a warning if <tt>#attr["UID"]</tt> is present
|
587
|
+
# but not identical to #uid.
|
588
|
+
def initialize(...)
|
589
|
+
super
|
590
|
+
attr and
|
591
|
+
attr_uid = attr["UID"] and
|
592
|
+
attr_uid != uid and
|
593
|
+
warn "#{self.class} UIDs do not match (#{attr_uid} != #{uid})"
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
data/lib/net/imap/flags.rb
CHANGED
@@ -71,7 +71,7 @@ module Net
|
|
71
71
|
# Mailbox name attributes are not case-sensitive. <em>The current
|
72
72
|
# implementation</em> normalizes mailbox attribute case using
|
73
73
|
# String#capitalize, such as +:Noselect+ (not +:NoSelect+). The constants
|
74
|
-
# (such as NO_SELECT) can also be used for comparison. The
|
74
|
+
# (such as NO_SELECT) can also be used for comparison. The constants have
|
75
75
|
# been defined both with and without underscores between words.
|
76
76
|
#
|
77
77
|
# <em>The descriptions here were copied from</em> {[RFC-9051 §
|