net-imap 0.4.19 → 0.5.0
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/Gemfile +7 -1
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +11 -0
- data/lib/net/imap/config.rb +36 -79
- data/lib/net/imap/data_encoding.rb +3 -3
- data/lib/net/imap/deprecated_client_options.rb +6 -3
- data/lib/net/imap/errors.rb +6 -0
- data/lib/net/imap/response_data.rb +60 -96
- data/lib/net/imap/response_parser.rb +18 -45
- data/lib/net/imap/sasl/authentication_exchange.rb +52 -20
- data/lib/net/imap/sasl/authenticators.rb +8 -4
- data/lib/net/imap/sasl/client_adapter.rb +77 -26
- data/lib/net/imap/sasl/cram_md5_authenticator.rb +1 -1
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +213 -51
- data/lib/net/imap/sasl/login_authenticator.rb +2 -1
- data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
- data/lib/net/imap/sasl.rb +6 -3
- data/lib/net/imap/sasl_adapter.rb +0 -1
- data/lib/net/imap/sequence_set.rb +70 -213
- data/lib/net/imap.rb +29 -55
- data/net-imap.gemspec +1 -1
- metadata +7 -5
- data/lib/net/imap/uidplus_data.rb +0 -326
data/lib/net/imap.rb
CHANGED
@@ -719,7 +719,7 @@ module Net
|
|
719
719
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
720
720
|
#
|
721
721
|
class IMAP < Protocol
|
722
|
-
VERSION = "0.
|
722
|
+
VERSION = "0.5.0"
|
723
723
|
|
724
724
|
# Aliases for supported capabilities, to be used with the #enable command.
|
725
725
|
ENABLE_ALIASES = {
|
@@ -946,9 +946,6 @@ module Net
|
|
946
946
|
@sock = tcp_socket(@host, @port)
|
947
947
|
start_tls_session if ssl_ctx
|
948
948
|
start_imap_connection
|
949
|
-
|
950
|
-
# DEPRECATED: to remove in next version
|
951
|
-
@client_thread = Thread.current
|
952
949
|
end
|
953
950
|
|
954
951
|
# Returns true after the TLS negotiation has completed and the remote
|
@@ -956,11 +953,6 @@ module Net
|
|
956
953
|
# but peer verification was disabled.
|
957
954
|
def tls_verified?; @tls_verified end
|
958
955
|
|
959
|
-
def client_thread # :nodoc:
|
960
|
-
warn "Net::IMAP#client_thread is deprecated and will be removed soon."
|
961
|
-
@client_thread
|
962
|
-
end
|
963
|
-
|
964
956
|
# Disconnects from the server.
|
965
957
|
#
|
966
958
|
# Related: #logout, #logout!
|
@@ -1222,21 +1214,13 @@ module Net
|
|
1222
1214
|
#
|
1223
1215
|
def starttls(**options)
|
1224
1216
|
@ssl_ctx_params, @ssl_ctx = build_ssl_ctx(options)
|
1225
|
-
|
1226
|
-
ok = send_command("STARTTLS") do |resp|
|
1217
|
+
send_command("STARTTLS") do |resp|
|
1227
1218
|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
|
1228
1219
|
clear_cached_capabilities
|
1229
1220
|
clear_responses
|
1230
1221
|
start_tls_session
|
1231
1222
|
end
|
1232
|
-
rescue Exception => error
|
1233
|
-
raise # note that the error backtrace is in the receiver_thread
|
1234
|
-
end
|
1235
|
-
if error
|
1236
|
-
disconnect
|
1237
|
-
raise error
|
1238
1223
|
end
|
1239
|
-
ok
|
1240
1224
|
end
|
1241
1225
|
|
1242
1226
|
# :call-seq:
|
@@ -1252,6 +1236,9 @@ module Net
|
|
1252
1236
|
# +SASL-IR+ capability, below). Defaults to the #config value for
|
1253
1237
|
# {sasl_ir}[rdoc-ref:Config#sasl_ir], which defaults to +true+.
|
1254
1238
|
#
|
1239
|
+
# The +registry+ kwarg can be used to select the mechanism implementation
|
1240
|
+
# from a custom registry. See SASL.authenticator and SASL::Authenticators.
|
1241
|
+
#
|
1255
1242
|
# All other arguments are forwarded to the registered SASL authenticator for
|
1256
1243
|
# the requested mechanism. <em>The documentation for each individual
|
1257
1244
|
# mechanism must be consulted for its specific parameters.</em>
|
@@ -1346,29 +1333,9 @@ module Net
|
|
1346
1333
|
# Previously cached #capabilities will be cleared when this method
|
1347
1334
|
# completes. If the TaggedResponse to #authenticate includes updated
|
1348
1335
|
# capabilities, they will be cached.
|
1349
|
-
def authenticate(
|
1350
|
-
|
1351
|
-
|
1352
|
-
mechanism = mechanism.to_s.tr("_", "-").upcase
|
1353
|
-
authenticator = SASL.authenticator(mechanism, *creds, **props, &callback)
|
1354
|
-
cmdargs = ["AUTHENTICATE", mechanism]
|
1355
|
-
if sasl_ir && capable?("SASL-IR") && auth_capable?(mechanism) &&
|
1356
|
-
authenticator.respond_to?(:initial_response?) &&
|
1357
|
-
authenticator.initial_response?
|
1358
|
-
response = authenticator.process(nil)
|
1359
|
-
cmdargs << (response.empty? ? "=" : [response].pack("m0"))
|
1360
|
-
end
|
1361
|
-
result = send_command_with_continuations(*cmdargs) {|data|
|
1362
|
-
challenge = data.unpack1("m")
|
1363
|
-
response = authenticator.process challenge
|
1364
|
-
[response].pack("m0")
|
1365
|
-
}
|
1366
|
-
if authenticator.respond_to?(:done?) && !authenticator.done?
|
1367
|
-
logout!
|
1368
|
-
raise SASL::AuthenticationIncomplete, result
|
1369
|
-
end
|
1370
|
-
@capabilities = capabilities_from_resp_code result
|
1371
|
-
result
|
1336
|
+
def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
|
1337
|
+
sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
|
1338
|
+
.tap { @capabilities = capabilities_from_resp_code _1 }
|
1372
1339
|
end
|
1373
1340
|
|
1374
1341
|
# Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
|
@@ -1388,13 +1355,9 @@ module Net
|
|
1388
1355
|
# ===== Capabilities
|
1389
1356
|
#
|
1390
1357
|
# An IMAP client MUST NOT call #login when the server advertises the
|
1391
|
-
# +LOGINDISABLED+ capability.
|
1392
|
-
#
|
1393
|
-
#
|
1394
|
-
# raise "Remote server has disabled the login command"
|
1395
|
-
# else
|
1396
|
-
# imap.login username, password
|
1397
|
-
# end
|
1358
|
+
# +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
|
1359
|
+
# LoginDisabledError when that capability is present. See
|
1360
|
+
# Config#enforce_logindisabled.
|
1398
1361
|
#
|
1399
1362
|
# Server capabilities may change after #starttls, #login, and #authenticate.
|
1400
1363
|
# Cached capabilities _must_ be invalidated after this method completes.
|
@@ -1402,6 +1365,9 @@ module Net
|
|
1402
1365
|
# ResponseCode.
|
1403
1366
|
#
|
1404
1367
|
def login(user, password)
|
1368
|
+
if enforce_logindisabled? && capability?("LOGINDISABLED")
|
1369
|
+
raise LoginDisabledError
|
1370
|
+
end
|
1405
1371
|
send_command("LOGIN", user, password)
|
1406
1372
|
.tap { @capabilities = capabilities_from_resp_code _1 }
|
1407
1373
|
end
|
@@ -1958,7 +1924,7 @@ module Net
|
|
1958
1924
|
# [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
|
1959
1925
|
def uid_expunge(uid_set)
|
1960
1926
|
synchronize do
|
1961
|
-
send_command("UID EXPUNGE",
|
1927
|
+
send_command("UID EXPUNGE", SequenceSet.new(uid_set))
|
1962
1928
|
clear_responses("EXPUNGE")
|
1963
1929
|
end
|
1964
1930
|
end
|
@@ -2616,7 +2582,7 @@ module Net
|
|
2616
2582
|
when :raise
|
2617
2583
|
raise ArgumentError, RESPONSES_DEPRECATION_MSG
|
2618
2584
|
when :warn
|
2619
|
-
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1)
|
2585
|
+
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated)
|
2620
2586
|
when :frozen_dup
|
2621
2587
|
synchronize {
|
2622
2588
|
responses = @responses.transform_values(&:freeze)
|
@@ -2965,6 +2931,14 @@ module Net
|
|
2965
2931
|
end
|
2966
2932
|
end
|
2967
2933
|
|
2934
|
+
def enforce_logindisabled?
|
2935
|
+
if config.enforce_logindisabled == :when_capabilities_cached
|
2936
|
+
capabilities_cached?
|
2937
|
+
else
|
2938
|
+
config.enforce_logindisabled
|
2939
|
+
end
|
2940
|
+
end
|
2941
|
+
|
2968
2942
|
def search_internal(cmd, keys, charset)
|
2969
2943
|
if keys.instance_of?(String)
|
2970
2944
|
keys = [RawData.new(keys)]
|
@@ -2998,9 +2972,9 @@ module Net
|
|
2998
2972
|
synchronize do
|
2999
2973
|
clear_responses("FETCH")
|
3000
2974
|
if mod
|
3001
|
-
send_command(cmd,
|
2975
|
+
send_command(cmd, SequenceSet.new(set), attr, mod)
|
3002
2976
|
else
|
3003
|
-
send_command(cmd,
|
2977
|
+
send_command(cmd, SequenceSet.new(set), attr)
|
3004
2978
|
end
|
3005
2979
|
clear_responses("FETCH")
|
3006
2980
|
end
|
@@ -3008,7 +2982,7 @@ module Net
|
|
3008
2982
|
|
3009
2983
|
def store_internal(cmd, set, attr, flags, unchangedsince: nil)
|
3010
2984
|
attr = RawData.new(attr) if attr.instance_of?(String)
|
3011
|
-
args = [
|
2985
|
+
args = [SequenceSet.new(set)]
|
3012
2986
|
args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
|
3013
2987
|
args << attr << flags
|
3014
2988
|
synchronize do
|
@@ -3019,7 +2993,7 @@ module Net
|
|
3019
2993
|
end
|
3020
2994
|
|
3021
2995
|
def copy_internal(cmd, set, mailbox)
|
3022
|
-
send_command(cmd,
|
2996
|
+
send_command(cmd, SequenceSet.new(set), mailbox)
|
3023
2997
|
end
|
3024
2998
|
|
3025
2999
|
def sort_internal(cmd, sort_keys, search_keys, charset)
|
@@ -3050,7 +3024,7 @@ module Net
|
|
3050
3024
|
keys.collect! do |i|
|
3051
3025
|
case i
|
3052
3026
|
when -1, Range, Array
|
3053
|
-
|
3027
|
+
SequenceSet.new(i)
|
3054
3028
|
else
|
3055
3029
|
i
|
3056
3030
|
end
|
data/net-imap.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.summary = %q{Ruby client api for Internet Message Access Protocol}
|
17
17
|
spec.description = %q{Ruby client api for Internet Message Access Protocol}
|
18
18
|
spec.homepage = "https://github.com/ruby/net-imap"
|
19
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0")
|
20
20
|
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
21
21
|
|
22
22
|
spec.metadata["homepage_uri"] = spec.homepage
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-imap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
- nicholas a. evans
|
9
|
+
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2024-10-16 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: net-protocol
|
@@ -94,7 +95,6 @@ files:
|
|
94
95
|
- lib/net/imap/stringprep/saslprep_tables.rb
|
95
96
|
- lib/net/imap/stringprep/tables.rb
|
96
97
|
- lib/net/imap/stringprep/trace.rb
|
97
|
-
- lib/net/imap/uidplus_data.rb
|
98
98
|
- net-imap.gemspec
|
99
99
|
- rakelib/benchmarks.rake
|
100
100
|
- rakelib/rdoc.rake
|
@@ -110,6 +110,7 @@ metadata:
|
|
110
110
|
homepage_uri: https://github.com/ruby/net-imap
|
111
111
|
source_code_uri: https://github.com/ruby/net-imap
|
112
112
|
changelog_uri: https://github.com/ruby/net-imap/releases
|
113
|
+
post_install_message:
|
113
114
|
rdoc_options: []
|
114
115
|
require_paths:
|
115
116
|
- lib
|
@@ -117,14 +118,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
118
|
requirements:
|
118
119
|
- - ">="
|
119
120
|
- !ruby/object:Gem::Version
|
120
|
-
version:
|
121
|
+
version: 3.1.0
|
121
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
123
|
requirements:
|
123
124
|
- - ">="
|
124
125
|
- !ruby/object:Gem::Version
|
125
126
|
version: '0'
|
126
127
|
requirements: []
|
127
|
-
rubygems_version: 3.
|
128
|
+
rubygems_version: 3.5.16
|
129
|
+
signing_key:
|
128
130
|
specification_version: 4
|
129
131
|
summary: Ruby client api for Internet Message Access Protocol
|
130
132
|
test_files: []
|
@@ -1,326 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Net
|
4
|
-
class IMAP < Protocol
|
5
|
-
|
6
|
-
# *NOTE:* <em>UIDPlusData is deprecated and will be removed in the +0.6.0+
|
7
|
-
# release.</em> To use AppendUIDData and CopyUIDData before +0.6.0+, set
|
8
|
-
# Config#parser_use_deprecated_uidplus_data to +false+.
|
9
|
-
#
|
10
|
-
# UIDPlusData represents the ResponseCode#data that accompanies the
|
11
|
-
# +APPENDUID+ and +COPYUID+ {response codes}[rdoc-ref:ResponseCode].
|
12
|
-
#
|
13
|
-
# A server that supports +UIDPLUS+ should send UIDPlusData in response to
|
14
|
-
# the append[rdoc-ref:Net::IMAP#append], copy[rdoc-ref:Net::IMAP#copy],
|
15
|
-
# move[rdoc-ref:Net::IMAP#move], {uid copy}[rdoc-ref:Net::IMAP#uid_copy],
|
16
|
-
# and {uid move}[rdoc-ref:Net::IMAP#uid_move] commands---unless the
|
17
|
-
# destination mailbox reports +UIDNOTSTICKY+.
|
18
|
-
#
|
19
|
-
# Note that append[rdoc-ref:Net::IMAP#append], copy[rdoc-ref:Net::IMAP#copy]
|
20
|
-
# and {uid_copy}[rdoc-ref:Net::IMAP#uid_copy] return UIDPlusData in their
|
21
|
-
# TaggedResponse. But move[rdoc-ref:Net::IMAP#copy] and
|
22
|
-
# {uid_move}[rdoc-ref:Net::IMAP#uid_move] _should_ send UIDPlusData in an
|
23
|
-
# UntaggedResponse response before sending their TaggedResponse. However
|
24
|
-
# some servers do send UIDPlusData in the TaggedResponse for +MOVE+
|
25
|
-
# commands---this complies with the older +UIDPLUS+ specification but is
|
26
|
-
# discouraged by the +MOVE+ extension and disallowed by +IMAP4rev2+.
|
27
|
-
#
|
28
|
-
# == Required capability
|
29
|
-
# Requires either +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315]]
|
30
|
-
# or +IMAP4rev2+ capability.
|
31
|
-
#
|
32
|
-
class UIDPlusData < Struct.new(:uidvalidity, :source_uids, :assigned_uids)
|
33
|
-
##
|
34
|
-
# method: uidvalidity
|
35
|
-
# :call-seq: uidvalidity -> nonzero uint32
|
36
|
-
#
|
37
|
-
# The UIDVALIDITY of the destination mailbox.
|
38
|
-
|
39
|
-
##
|
40
|
-
# method: source_uids
|
41
|
-
# :call-seq: source_uids -> nil or an array of nonzero uint32
|
42
|
-
#
|
43
|
-
# The UIDs of the copied or moved messages.
|
44
|
-
#
|
45
|
-
# Note:: Returns +nil+ for Net::IMAP#append.
|
46
|
-
|
47
|
-
##
|
48
|
-
# method: assigned_uids
|
49
|
-
# :call-seq: assigned_uids -> an array of nonzero uint32
|
50
|
-
#
|
51
|
-
# The newly assigned UIDs of the copied, moved, or appended messages.
|
52
|
-
#
|
53
|
-
# Note:: This always returns an array, even when it contains only one UID.
|
54
|
-
|
55
|
-
##
|
56
|
-
# :call-seq: uid_mapping -> nil or a hash
|
57
|
-
#
|
58
|
-
# Returns a hash mapping each source UID to the newly assigned destination
|
59
|
-
# UID.
|
60
|
-
#
|
61
|
-
# Note:: Returns +nil+ for Net::IMAP#append.
|
62
|
-
def uid_mapping
|
63
|
-
source_uids&.zip(assigned_uids)&.to_h
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# This replaces the `Data.define` polyfill that's used by net-imap 0.5.
|
68
|
-
class Data_define__uidvalidity___assigned_uids_ # :no-doc:
|
69
|
-
attr_reader :uidvalidity, :assigned_uids
|
70
|
-
|
71
|
-
def self.[](...) new(...) end
|
72
|
-
def self.new(uidvalidity = (args = false; nil),
|
73
|
-
assigned_uids = nil,
|
74
|
-
**kwargs)
|
75
|
-
if kwargs.empty?
|
76
|
-
super(uidvalidity: uidvalidity, assigned_uids: assigned_uids)
|
77
|
-
elsif !args
|
78
|
-
super
|
79
|
-
else
|
80
|
-
raise ArgumentError, "sent both positional and keyword args"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def ==(other)
|
85
|
-
self.class == other.class &&
|
86
|
-
self.uidvalidity == other.uidvalidity &&
|
87
|
-
self.assigned_uids == other.assigned_uids
|
88
|
-
end
|
89
|
-
|
90
|
-
def eql?(other)
|
91
|
-
self.class.eql?(other.class) &&
|
92
|
-
self.uidvalidity.eql?(other.uidvalidity) &&
|
93
|
-
self.assigned_uids.eql?(other.assigned_uids)
|
94
|
-
end
|
95
|
-
|
96
|
-
def hash; [self.class, uidvalidity, assigned_uids].hash end
|
97
|
-
|
98
|
-
def initialize(uidvalidity:, assigned_uids:)
|
99
|
-
@uidvalidity = uidvalidity
|
100
|
-
@assigned_uids = assigned_uids
|
101
|
-
freeze
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# >>>
|
106
|
-
# *NOTE:* <em>AppendUIDData will replace UIDPlusData for +APPENDUID+ in the
|
107
|
-
# +0.6.0+ release.</em> To use AppendUIDData before +0.6.0+, set
|
108
|
-
# Config#parser_use_deprecated_uidplus_data to +false+.
|
109
|
-
#
|
110
|
-
# AppendUIDData represents the ResponseCode#data that accompanies the
|
111
|
-
# +APPENDUID+ {response code}[rdoc-ref:ResponseCode].
|
112
|
-
#
|
113
|
-
# A server that supports +UIDPLUS+ (or +IMAP4rev2+) should send
|
114
|
-
# AppendUIDData inside every TaggedResponse returned by the
|
115
|
-
# append[rdoc-ref:Net::IMAP#append] command---unless the target mailbox
|
116
|
-
# reports +UIDNOTSTICKY+.
|
117
|
-
#
|
118
|
-
# == Required capability
|
119
|
-
# Requires either +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315]]
|
120
|
-
# or +IMAP4rev2+ capability.
|
121
|
-
class AppendUIDData < Data_define__uidvalidity___assigned_uids_
|
122
|
-
def initialize(uidvalidity:, assigned_uids:)
|
123
|
-
uidvalidity = Integer(uidvalidity)
|
124
|
-
assigned_uids = SequenceSet[assigned_uids]
|
125
|
-
NumValidator.ensure_nz_number(uidvalidity)
|
126
|
-
if assigned_uids.include_star?
|
127
|
-
raise DataFormatError, "uid-set cannot contain '*'"
|
128
|
-
end
|
129
|
-
super
|
130
|
-
end
|
131
|
-
|
132
|
-
##
|
133
|
-
# attr_reader: uidvalidity
|
134
|
-
# :call-seq: uidvalidity -> nonzero uint32
|
135
|
-
#
|
136
|
-
# The UIDVALIDITY of the destination mailbox.
|
137
|
-
|
138
|
-
##
|
139
|
-
# attr_reader: assigned_uids
|
140
|
-
#
|
141
|
-
# A SequenceSet with the newly assigned UIDs of the appended messages.
|
142
|
-
|
143
|
-
# Returns the number of messages that have been appended.
|
144
|
-
def size
|
145
|
-
assigned_uids.count_with_duplicates
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# This replaces the `Data.define` polyfill that's used by net-imap 0.5.
|
150
|
-
class Data_define__uidvalidity___source_uids___assigned_uids_ # :no-doc:
|
151
|
-
attr_reader :uidvalidity, :source_uids, :assigned_uids
|
152
|
-
|
153
|
-
def self.[](...) new(...) end
|
154
|
-
def self.new(uidvalidity = (args = false; nil),
|
155
|
-
source_uids = nil,
|
156
|
-
assigned_uids = nil,
|
157
|
-
**kwargs)
|
158
|
-
if kwargs.empty?
|
159
|
-
super(uidvalidity: uidvalidity,
|
160
|
-
source_uids: source_uids,
|
161
|
-
assigned_uids: assigned_uids)
|
162
|
-
elsif !args
|
163
|
-
super(**kwargs)
|
164
|
-
else
|
165
|
-
raise ArgumentError, "sent both positional and keyword args"
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def initialize(uidvalidity:, source_uids:, assigned_uids:)
|
170
|
-
@uidvalidity = uidvalidity
|
171
|
-
@source_uids = source_uids
|
172
|
-
@assigned_uids = assigned_uids
|
173
|
-
freeze
|
174
|
-
end
|
175
|
-
|
176
|
-
def ==(other)
|
177
|
-
self.class == other.class &&
|
178
|
-
self.uidvalidity == other.uidvalidity &&
|
179
|
-
self.source_uids == other.source_uids
|
180
|
-
self.assigned_uids == other.assigned_uids
|
181
|
-
end
|
182
|
-
|
183
|
-
def eql?(other)
|
184
|
-
self.class.eql?(other.class) &&
|
185
|
-
self.uidvalidity.eql?(other.uidvalidity) &&
|
186
|
-
self.source_uids.eql?(other.source_uids)
|
187
|
-
self.assigned_uids.eql?(other.assigned_uids)
|
188
|
-
end
|
189
|
-
|
190
|
-
def hash; [self.class, uidvalidity, source_uids, assigned_uids].hash end
|
191
|
-
end
|
192
|
-
|
193
|
-
# >>>
|
194
|
-
# *NOTE:* <em>CopyUIDData will replace UIDPlusData for +COPYUID+ in the
|
195
|
-
# +0.6.0+ release.</em> To use CopyUIDData before +0.6.0+, set
|
196
|
-
# Config#parser_use_deprecated_uidplus_data to +false+.
|
197
|
-
#
|
198
|
-
# CopyUIDData represents the ResponseCode#data that accompanies the
|
199
|
-
# +COPYUID+ {response code}[rdoc-ref:ResponseCode].
|
200
|
-
#
|
201
|
-
# A server that supports +UIDPLUS+ (or +IMAP4rev2+) should send CopyUIDData
|
202
|
-
# in response to
|
203
|
-
# copy[rdoc-ref:Net::IMAP#copy], {uid_copy}[rdoc-ref:Net::IMAP#uid_copy],
|
204
|
-
# move[rdoc-ref:Net::IMAP#copy], and {uid_move}[rdoc-ref:Net::IMAP#uid_move]
|
205
|
-
# commands---unless the destination mailbox reports +UIDNOTSTICKY+.
|
206
|
-
#
|
207
|
-
# Note that copy[rdoc-ref:Net::IMAP#copy] and
|
208
|
-
# {uid_copy}[rdoc-ref:Net::IMAP#uid_copy] return CopyUIDData in their
|
209
|
-
# TaggedResponse. But move[rdoc-ref:Net::IMAP#copy] and
|
210
|
-
# {uid_move}[rdoc-ref:Net::IMAP#uid_move] _should_ send CopyUIDData in an
|
211
|
-
# UntaggedResponse response before sending their TaggedResponse. However
|
212
|
-
# some servers do send CopyUIDData in the TaggedResponse for +MOVE+
|
213
|
-
# commands---this complies with the older +UIDPLUS+ specification but is
|
214
|
-
# discouraged by the +MOVE+ extension and disallowed by +IMAP4rev2+.
|
215
|
-
#
|
216
|
-
# == Required capability
|
217
|
-
# Requires either +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315]]
|
218
|
-
# or +IMAP4rev2+ capability.
|
219
|
-
class CopyUIDData < Data_define__uidvalidity___source_uids___assigned_uids_
|
220
|
-
def initialize(uidvalidity:, source_uids:, assigned_uids:)
|
221
|
-
uidvalidity = Integer(uidvalidity)
|
222
|
-
source_uids = SequenceSet[source_uids]
|
223
|
-
assigned_uids = SequenceSet[assigned_uids]
|
224
|
-
NumValidator.ensure_nz_number(uidvalidity)
|
225
|
-
if source_uids.include_star? || assigned_uids.include_star?
|
226
|
-
raise DataFormatError, "uid-set cannot contain '*'"
|
227
|
-
elsif source_uids.count_with_duplicates != assigned_uids.count_with_duplicates
|
228
|
-
raise DataFormatError, "mismatched uid-set sizes for %s and %s" % [
|
229
|
-
source_uids, assigned_uids
|
230
|
-
]
|
231
|
-
end
|
232
|
-
super
|
233
|
-
end
|
234
|
-
|
235
|
-
##
|
236
|
-
# attr_reader: uidvalidity
|
237
|
-
#
|
238
|
-
# The +UIDVALIDITY+ of the destination mailbox (a nonzero unsigned 32 bit
|
239
|
-
# integer).
|
240
|
-
|
241
|
-
##
|
242
|
-
# attr_reader: source_uids
|
243
|
-
#
|
244
|
-
# A SequenceSet with the original UIDs of the copied or moved messages.
|
245
|
-
|
246
|
-
##
|
247
|
-
# attr_reader: assigned_uids
|
248
|
-
#
|
249
|
-
# A SequenceSet with the newly assigned UIDs of the copied or moved
|
250
|
-
# messages.
|
251
|
-
|
252
|
-
# Returns the number of messages that have been copied or moved.
|
253
|
-
# source_uids and the assigned_uids will both the same number of UIDs.
|
254
|
-
def size
|
255
|
-
assigned_uids.count_with_duplicates
|
256
|
-
end
|
257
|
-
|
258
|
-
# :call-seq:
|
259
|
-
# assigned_uid_for(source_uid) -> uid
|
260
|
-
# self[source_uid] -> uid
|
261
|
-
#
|
262
|
-
# Returns the UID in the destination mailbox for the message that was
|
263
|
-
# copied from +source_uid+ in the source mailbox.
|
264
|
-
#
|
265
|
-
# This is the reverse of #source_uid_for.
|
266
|
-
#
|
267
|
-
# Related: source_uid_for, each_uid_pair, uid_mapping
|
268
|
-
def assigned_uid_for(source_uid)
|
269
|
-
idx = source_uids.find_ordered_index(source_uid) and
|
270
|
-
assigned_uids.ordered_at(idx)
|
271
|
-
end
|
272
|
-
alias :[] :assigned_uid_for
|
273
|
-
|
274
|
-
# :call-seq:
|
275
|
-
# source_uid_for(assigned_uid) -> uid
|
276
|
-
#
|
277
|
-
# Returns the UID in the source mailbox for the message that was copied to
|
278
|
-
# +assigned_uid+ in the source mailbox.
|
279
|
-
#
|
280
|
-
# This is the reverse of #assigned_uid_for.
|
281
|
-
#
|
282
|
-
# Related: assigned_uid_for, each_uid_pair, uid_mapping
|
283
|
-
def source_uid_for(assigned_uid)
|
284
|
-
idx = assigned_uids.find_ordered_index(assigned_uid) and
|
285
|
-
source_uids.ordered_at(idx)
|
286
|
-
end
|
287
|
-
|
288
|
-
# Yields a pair of UIDs for each copied message. The first is the
|
289
|
-
# message's UID in the source mailbox and the second is the UID in the
|
290
|
-
# destination mailbox.
|
291
|
-
#
|
292
|
-
# Returns an enumerator when no block is given.
|
293
|
-
#
|
294
|
-
# Please note the warning on uid_mapping before calling methods like
|
295
|
-
# +to_h+ or +to_a+ on the returned enumerator.
|
296
|
-
#
|
297
|
-
# Related: uid_mapping, assigned_uid_for, source_uid_for
|
298
|
-
def each_uid_pair
|
299
|
-
return enum_for(__method__) unless block_given?
|
300
|
-
source_uids.each_ordered_number.lazy
|
301
|
-
.zip(assigned_uids.each_ordered_number.lazy) do
|
302
|
-
|source_uid, assigned_uid|
|
303
|
-
yield source_uid, assigned_uid
|
304
|
-
end
|
305
|
-
end
|
306
|
-
alias each_pair each_uid_pair
|
307
|
-
alias each each_uid_pair
|
308
|
-
|
309
|
-
# :call-seq: uid_mapping -> hash
|
310
|
-
#
|
311
|
-
# Returns a hash mapping each source UID to the newly assigned destination
|
312
|
-
# UID.
|
313
|
-
#
|
314
|
-
# <em>*Warning:*</em> The hash that is created may consume _much_ more
|
315
|
-
# memory than the data used to create it. When handling responses from an
|
316
|
-
# untrusted server, check #size before calling this method.
|
317
|
-
#
|
318
|
-
# Related: each_uid_pair, assigned_uid_for, source_uid_for
|
319
|
-
def uid_mapping
|
320
|
-
each_uid_pair.to_h
|
321
|
-
end
|
322
|
-
|
323
|
-
end
|
324
|
-
|
325
|
-
end
|
326
|
-
end
|