imap-backup 14.6.1 → 15.0.1
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/imap-backup.gemspec +1 -1
- data/lib/imap/backup/account/folder_backup.rb +12 -15
- data/lib/imap/backup/client/automatic_login_wrapper.rb +3 -3
- data/lib/imap/backup/naming.rb +1 -1
- data/lib/imap/backup/serializer/delayed_metadata_serializer.rb +33 -5
- data/lib/imap/backup/serializer/imap.rb +23 -3
- data/lib/imap/backup/serializer.rb +2 -13
- data/lib/imap/backup/setup/asker.rb +1 -1
- data/lib/imap/backup/version.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3504dad0e3f788bcfa95b38065e0ff4035239886461689c478a2e991f5e06cf9
|
4
|
+
data.tar.gz: 7d1151b5fb25f2d84ae2013f8f9f74fee7f998ca36b29333bf44151e52726376
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ec40ec413bd6bedce02d4c823ae1654c06585223532d1260bf01fe4ef0e8ba6e0b8c25c7adf0d2b39f8ff29c5199251d07fb9234a75a3ac50856075c91ccc52
|
7
|
+
data.tar.gz: d31020db8b37295d8d7209758161ce4fe5d16869a6976f3538e12b2d7a74f3cb363328d0dcd79ce665a2b113cf7f6289794ee328ded6e8a73cb544c4d0897428
|
data/imap-backup.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
|
|
18
18
|
|
19
19
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
20
20
|
gem.require_paths = ["lib"]
|
21
|
-
gem.required_ruby_version = ">=
|
21
|
+
gem.required_ruby_version = ">= 3.0"
|
22
22
|
|
23
23
|
gem.add_runtime_dependency "highline"
|
24
24
|
gem.add_runtime_dependency "mail", "2.7.1"
|
@@ -29,11 +29,13 @@ module Imap::Backup
|
|
29
29
|
|
30
30
|
serializer.apply_uid_validity(folder.uid_validity)
|
31
31
|
|
32
|
-
|
32
|
+
serializer.transaction do
|
33
33
|
downloader.run
|
34
|
+
FlagRefresher.new(folder, serializer).run if account.mirror_mode || refresh
|
34
35
|
end
|
35
|
-
|
36
|
-
|
36
|
+
# After the transaction the serializer will have any appended messages
|
37
|
+
# so we can check differences between the server and the local backup
|
38
|
+
LocalOnlyMessageDeleter.new(folder, raw_serializer).run if account.mirror_mode
|
37
39
|
end
|
38
40
|
|
39
41
|
private
|
@@ -55,34 +57,29 @@ module Imap::Backup
|
|
55
57
|
true
|
56
58
|
end
|
57
59
|
|
58
|
-
def clean_up
|
59
|
-
LocalOnlyMessageDeleter.new(folder, serializer).run if account.mirror_mode
|
60
|
-
FlagRefresher.new(folder, serializer).run if account.mirror_mode || refresh
|
61
|
-
end
|
62
|
-
|
63
60
|
def downloader
|
64
61
|
@downloader ||= Downloader.new(
|
65
62
|
folder,
|
66
|
-
|
63
|
+
serializer,
|
67
64
|
multi_fetch_size: account.multi_fetch_size,
|
68
65
|
reset_seen_flags_after_fetch: account.reset_seen_flags_after_fetch
|
69
66
|
)
|
70
67
|
end
|
71
68
|
|
72
|
-
def
|
73
|
-
@
|
69
|
+
def serializer
|
70
|
+
@serializer ||=
|
74
71
|
case account.download_strategy
|
75
72
|
when "direct"
|
76
|
-
|
73
|
+
raw_serializer
|
77
74
|
when "delay_metadata"
|
78
|
-
Serializer::DelayedMetadataSerializer.new(serializer:
|
75
|
+
Serializer::DelayedMetadataSerializer.new(serializer: raw_serializer)
|
79
76
|
else
|
80
77
|
raise "Unknown download strategy '#{account.download_strategy}'"
|
81
78
|
end
|
82
79
|
end
|
83
80
|
|
84
|
-
def
|
85
|
-
@
|
81
|
+
def raw_serializer
|
82
|
+
@raw_serializer ||= Serializer.new(account.local_path, folder.name)
|
86
83
|
end
|
87
84
|
end
|
88
85
|
end
|
@@ -23,12 +23,12 @@ module Imap::Backup
|
|
23
23
|
# Proxies calls to the client.
|
24
24
|
# Before the first call does login
|
25
25
|
# @return the return value of the client method called
|
26
|
-
def method_missing(method_name,
|
26
|
+
def method_missing(method_name, ...)
|
27
27
|
if login_called
|
28
|
-
client.send(method_name,
|
28
|
+
client.send(method_name, ...)
|
29
29
|
else
|
30
30
|
do_first_login
|
31
|
-
client.send(method_name,
|
31
|
+
client.send(method_name, ...) if method_name != :login
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
data/lib/imap/backup/naming.rb
CHANGED
@@ -7,7 +7,7 @@ module Imap::Backup
|
|
7
7
|
# The characters that cannot be used in file names
|
8
8
|
INVALID_FILENAME_CHARACTERS = ":%;".freeze
|
9
9
|
# A regular expression that captures each disallowed character
|
10
|
-
INVALID_FILENAME_CHARACTER_MATCH = /([#{INVALID_FILENAME_CHARACTERS}])
|
10
|
+
INVALID_FILENAME_CHARACTER_MATCH = /([#{INVALID_FILENAME_CHARACTERS}])/
|
11
11
|
|
12
12
|
# @param name [String] a folder name
|
13
13
|
# @return [String] the supplied string iwth disallowed characters replaced
|
@@ -10,7 +10,7 @@ module Imap; end
|
|
10
10
|
module Imap::Backup
|
11
11
|
class Serializer; end
|
12
12
|
|
13
|
-
# Wraps the Serializer, delaying metadata
|
13
|
+
# Wraps the Serializer, delaying metadata changes
|
14
14
|
class Serializer::DelayedMetadataSerializer
|
15
15
|
extend Forwardable
|
16
16
|
|
@@ -31,7 +31,7 @@ module Imap::Backup
|
|
31
31
|
def transaction(&block)
|
32
32
|
tsx.fail_in_transaction!(:transaction, message: "nested transactions are not supported")
|
33
33
|
|
34
|
-
tsx.begin({
|
34
|
+
tsx.begin({appends: [], updates: []}) do
|
35
35
|
mbox.transaction do
|
36
36
|
block.call
|
37
37
|
|
@@ -42,7 +42,21 @@ module Imap::Backup
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
#
|
45
|
+
# Sets the folder's UID validity via the serializer
|
46
|
+
#
|
47
|
+
# @param uid_validity [Integer] the UID validity to apply
|
48
|
+
# @raise [RuntimeError] if called inside a transaction
|
49
|
+
# @return [void]
|
50
|
+
def apply_uid_validity(uid_validity)
|
51
|
+
tsx.fail_in_transaction!(
|
52
|
+
:transaction,
|
53
|
+
message: "UID validity cannot be changed in a transaction"
|
54
|
+
)
|
55
|
+
|
56
|
+
serializer.apply_uid_validity(uid_validity)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Appends a message to the mbox file and adds the appended message's metadata
|
46
60
|
# to the transaction
|
47
61
|
#
|
48
62
|
# @param uid [Integer] the UID of the message
|
@@ -53,10 +67,21 @@ module Imap::Backup
|
|
53
67
|
tsx.fail_outside_transaction!(:append)
|
54
68
|
mboxrd_message = Email::Mboxrd::Message.new(message)
|
55
69
|
serialized = mboxrd_message.to_serialized
|
56
|
-
tsx.data[:
|
70
|
+
tsx.data[:appends] << {uid: uid, length: serialized.bytesize, flags: flags}
|
57
71
|
mbox.append(serialized)
|
58
72
|
end
|
59
73
|
|
74
|
+
# Stores changes to a message's metadata for later update
|
75
|
+
#
|
76
|
+
# @param uid [Integer] the UID of the message
|
77
|
+
# @param length [Integer] the length of the message
|
78
|
+
# @param flags [Array<Symbol>] the flags for the message
|
79
|
+
# @return [void]
|
80
|
+
def update(uid, length: nil, flags: nil)
|
81
|
+
tsx.fail_outside_transaction!(:update)
|
82
|
+
tsx.data[:updates] << {uid: uid, length: length, flags: flags}
|
83
|
+
end
|
84
|
+
|
60
85
|
private
|
61
86
|
|
62
87
|
attr_reader :serializer
|
@@ -64,9 +89,12 @@ module Imap::Backup
|
|
64
89
|
def commit
|
65
90
|
# rubocop:disable Lint/RescueException
|
66
91
|
imap.transaction do
|
67
|
-
tsx.data[:
|
92
|
+
tsx.data[:appends].each do |m|
|
68
93
|
imap.append m[:uid], m[:length], flags: m[:flags]
|
69
94
|
end
|
95
|
+
tsx.data[:updates].each do |m|
|
96
|
+
imap.update m[:uid], length: m[:length], flags: m[:flags]
|
97
|
+
end
|
70
98
|
rescue Exception => e
|
71
99
|
Logger.logger.error "#{self.class} handling #{e.class}"
|
72
100
|
imap.rollback
|
@@ -97,11 +97,27 @@ module Imap::Backup
|
|
97
97
|
save
|
98
98
|
end
|
99
99
|
|
100
|
-
#
|
100
|
+
# Updates a message's length and/or flags
|
101
|
+
# @param uid [Integer] the existing message's UID
|
102
|
+
# @param length [Integer] the length of the message (as stored on disk)
|
103
|
+
# @param flags [Array[Symbol]] the message's flags
|
104
|
+
# @raise [RuntimeError] if the UID does not exist
|
105
|
+
# @return [void]
|
106
|
+
def update(uid, length: nil, flags: nil)
|
107
|
+
index = messages.find_index { |m| m.uid == uid }
|
108
|
+
raise "UID #{uid} not found" if !index
|
109
|
+
|
110
|
+
messages[index].length = length if length
|
111
|
+
messages[index].flags = flags if flags
|
112
|
+
save
|
113
|
+
end
|
114
|
+
|
115
|
+
# Get a copy of message metadata
|
101
116
|
# @param uid [Integer] a message UID
|
102
117
|
# @return [Serializer::Message]
|
103
118
|
def get(uid)
|
104
|
-
messages.find { |m| m.uid == uid }
|
119
|
+
message = messages.find { |m| m.uid == uid }
|
120
|
+
message&.dup
|
105
121
|
end
|
106
122
|
|
107
123
|
# Deletes the metadata file
|
@@ -158,11 +174,15 @@ module Imap::Backup
|
|
158
174
|
messages.map(&:uid)
|
159
175
|
end
|
160
176
|
|
161
|
-
# Update a message's
|
177
|
+
# Update a message's UID
|
162
178
|
# @param old [Integer] the existing message UID
|
163
179
|
# @param new [Integer] the new UID to apply to the message
|
180
|
+
# @raise [RuntimeError] if the new UID already exists
|
164
181
|
# @return [void]
|
165
182
|
def update_uid(old, new)
|
183
|
+
existing = messages.find_index { |m| m.uid == new }
|
184
|
+
raise "UID #{new} already exists" if existing
|
185
|
+
|
166
186
|
index = messages.find_index { |m| m.uid == old }
|
167
187
|
return if index.nil?
|
168
188
|
|
@@ -28,6 +28,7 @@ module Imap::Backup
|
|
28
28
|
extend Forwardable
|
29
29
|
|
30
30
|
def_delegator :mbox, :pathname, :mbox_pathname
|
31
|
+
def_delegator :imap, :update
|
31
32
|
|
32
33
|
# Get message metadata
|
33
34
|
# @param uid [Integer] a message UID
|
@@ -77,7 +78,7 @@ module Imap::Backup
|
|
77
78
|
@validated = nil
|
78
79
|
end
|
79
80
|
|
80
|
-
# Calls the supplied block.
|
81
|
+
# Calls the supplied block without implementing transactional behaviour.
|
81
82
|
# This method is present so that this class implements the same
|
82
83
|
# interface as {DelayedMetadataSerializer}
|
83
84
|
# @param block [block] the block that is wrapped by the transaction
|
@@ -177,18 +178,6 @@ module Imap::Backup
|
|
177
178
|
appender.append(uid: uid, message: message, flags: flags)
|
178
179
|
end
|
179
180
|
|
180
|
-
# Updates a messages flags
|
181
|
-
# @param uid [Integer] the message's UID
|
182
|
-
# @param flags [Array<Symbol>] the flags to set on the message
|
183
|
-
# @return [void]
|
184
|
-
def update(uid, flags: nil)
|
185
|
-
message = imap.get(uid)
|
186
|
-
return if !message
|
187
|
-
|
188
|
-
message.flags = flags if flags
|
189
|
-
imap.save
|
190
|
-
end
|
191
|
-
|
192
181
|
# Enumerates over a series of messages.
|
193
182
|
# When called without a block, returns an Enumerator
|
194
183
|
# @param required_uids [Array<Integer>] the UIDs of the message to enumerate over
|
data/lib/imap/backup/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imap-backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 15.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Yates
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -226,7 +226,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
226
226
|
requirements:
|
227
227
|
- - ">="
|
228
228
|
- !ruby/object:Gem::Version
|
229
|
-
version: '
|
229
|
+
version: '3.0'
|
230
230
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
231
231
|
requirements:
|
232
232
|
- - ">="
|