imap-backup 9.4.0.pre1 → 10.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/docs/development.md +6 -0
  3. data/lib/email/mboxrd/message.rb +5 -13
  4. data/lib/imap/backup/account/backup.rb +65 -0
  5. data/lib/imap/backup/account/{connection/backup_folders.rb → backup_folders.rb} +12 -5
  6. data/lib/imap/backup/account/{connection/client_factory.rb → client_factory.rb} +11 -11
  7. data/lib/imap/backup/account/folder.rb +8 -14
  8. data/lib/imap/backup/account/folder_ensurer.rb +24 -0
  9. data/lib/imap/backup/account/local_only_folder_deleter.rb +26 -0
  10. data/lib/imap/backup/account/restore.rb +20 -0
  11. data/lib/imap/backup/account/serialized_folders.rb +41 -0
  12. data/lib/imap/backup/account.rb +16 -4
  13. data/lib/imap/backup/cli/backup.rb +6 -7
  14. data/lib/imap/backup/cli/folder_enumerator.rb +1 -1
  15. data/lib/imap/backup/cli/helpers.rb +15 -15
  16. data/lib/imap/backup/cli/local.rb +31 -19
  17. data/lib/imap/backup/cli/mirror.rb +1 -1
  18. data/lib/imap/backup/cli/remote.rb +8 -8
  19. data/lib/imap/backup/cli/restore.rb +10 -14
  20. data/lib/imap/backup/cli/stats.rb +8 -3
  21. data/lib/imap/backup/cli/utils.rb +14 -5
  22. data/lib/imap/backup/cli.rb +13 -9
  23. data/lib/imap/backup/client/default.rb +28 -5
  24. data/lib/imap/backup/configuration.rb +8 -2
  25. data/lib/imap/backup/downloader.rb +4 -1
  26. data/lib/imap/backup/file_mode.rb +16 -0
  27. data/lib/imap/backup/mirror.rb +1 -2
  28. data/lib/imap/backup/serializer/directory.rb +6 -4
  29. data/lib/imap/backup/serializer/folder_maker.rb +33 -0
  30. data/lib/imap/backup/serializer/permission_checker.rb +26 -0
  31. data/lib/imap/backup/serializer.rb +9 -3
  32. data/lib/imap/backup/setup/connection_tester.rb +1 -7
  33. data/lib/imap/backup/setup/folder_chooser.rb +9 -9
  34. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +34 -7
  35. data/lib/imap/backup/uploader.rb +1 -1
  36. data/lib/imap/backup/version.rb +3 -3
  37. data/lib/imap/backup.rb +0 -2
  38. metadata +14 -9
  39. data/lib/imap/backup/account/connection/folder_names.rb +0 -26
  40. data/lib/imap/backup/account/connection.rb +0 -136
  41. data/lib/imap/backup/utils.rb +0 -40
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: 9.4.0.pre1
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-16 00:00:00.000000000 Z
11
+ date: 2023-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -232,11 +232,14 @@ files:
232
232
  - lib/email/provider/unknown.rb
233
233
  - lib/imap/backup.rb
234
234
  - lib/imap/backup/account.rb
235
- - lib/imap/backup/account/connection.rb
236
- - lib/imap/backup/account/connection/backup_folders.rb
237
- - lib/imap/backup/account/connection/client_factory.rb
238
- - lib/imap/backup/account/connection/folder_names.rb
235
+ - lib/imap/backup/account/backup.rb
236
+ - lib/imap/backup/account/backup_folders.rb
237
+ - lib/imap/backup/account/client_factory.rb
239
238
  - lib/imap/backup/account/folder.rb
239
+ - lib/imap/backup/account/folder_ensurer.rb
240
+ - lib/imap/backup/account/local_only_folder_deleter.rb
241
+ - lib/imap/backup/account/restore.rb
242
+ - lib/imap/backup/account/serialized_folders.rb
240
243
  - lib/imap/backup/cli.rb
241
244
  - lib/imap/backup/cli/backup.rb
242
245
  - lib/imap/backup/cli/folder_enumerator.rb
@@ -253,6 +256,7 @@ files:
253
256
  - lib/imap/backup/client/default.rb
254
257
  - lib/imap/backup/configuration.rb
255
258
  - lib/imap/backup/downloader.rb
259
+ - lib/imap/backup/file_mode.rb
256
260
  - lib/imap/backup/flag_refresher.rb
257
261
  - lib/imap/backup/local_only_message_deleter.rb
258
262
  - lib/imap/backup/logger.rb
@@ -263,10 +267,12 @@ files:
263
267
  - lib/imap/backup/serializer.rb
264
268
  - lib/imap/backup/serializer/appender.rb
265
269
  - lib/imap/backup/serializer/directory.rb
270
+ - lib/imap/backup/serializer/folder_maker.rb
266
271
  - lib/imap/backup/serializer/imap.rb
267
272
  - lib/imap/backup/serializer/mbox.rb
268
273
  - lib/imap/backup/serializer/message.rb
269
274
  - lib/imap/backup/serializer/message_enumerator.rb
275
+ - lib/imap/backup/serializer/permission_checker.rb
270
276
  - lib/imap/backup/serializer/unused_name_finder.rb
271
277
  - lib/imap/backup/serializer/version2_migrator.rb
272
278
  - lib/imap/backup/setup.rb
@@ -280,7 +286,6 @@ files:
280
286
  - lib/imap/backup/setup/helpers.rb
281
287
  - lib/imap/backup/thunderbird/mailbox_exporter.rb
282
288
  - lib/imap/backup/uploader.rb
283
- - lib/imap/backup/utils.rb
284
289
  - lib/imap/backup/version.rb
285
290
  - lib/retry_on_error.rb
286
291
  - lib/text/sanitizer.rb
@@ -300,9 +305,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
300
305
  version: '2.6'
301
306
  required_rubygems_version: !ruby/object:Gem::Requirement
302
307
  requirements:
303
- - - ">"
308
+ - - ">="
304
309
  - !ruby/object:Gem::Version
305
- version: 1.3.1
310
+ version: '0'
306
311
  requirements: []
307
312
  rubygems_version: 3.3.7
308
313
  signing_key:
@@ -1,26 +0,0 @@
1
- module Imap::Backup
2
- class Account; end
3
- class Account::Connection; end
4
-
5
- class Account::Connection::FolderNames
6
- attr_reader :account
7
- attr_reader :client
8
-
9
- def initialize(client:, account:)
10
- @client = client
11
- @account = account
12
- end
13
-
14
- def run
15
- folder_names = client.list
16
-
17
- if folder_names.empty?
18
- message = "Unable to get folder list for account #{account.username}"
19
- Logger.logger.info message
20
- raise message
21
- end
22
-
23
- folder_names
24
- end
25
- end
26
- end
@@ -1,136 +0,0 @@
1
- require "imap/backup/client/apple_mail"
2
- require "imap/backup/client/default"
3
- require "imap/backup/account/connection/backup_folders"
4
- require "imap/backup/account/connection/client_factory"
5
- require "imap/backup/account/connection/folder_names"
6
- require "imap/backup/flag_refresher"
7
- require "imap/backup/local_only_message_deleter"
8
- require "imap/backup/serializer/directory"
9
-
10
- module Imap::Backup
11
- class Account; end
12
-
13
- class Account::Connection
14
- attr_reader :account
15
-
16
- def initialize(account)
17
- @account = account
18
- reset
19
- end
20
-
21
- def folder_names
22
- @folder_names ||= Account::Connection::FolderNames.new(client: client, account: account).run
23
- end
24
-
25
- def backup_folders
26
- @backup_folders ||=
27
- Account::Connection::BackupFolders.new(client: client, account: account).run
28
- end
29
-
30
- def namespaces
31
- client.namespace
32
- end
33
-
34
- def run_backup(refresh: false)
35
- Logger.logger.info "Running backup of account: #{account.username}"
36
- # start the connection so we get logging messages in the right order
37
- client
38
- ensure_account_folder
39
- if account.mirror_mode
40
- # Delete serialized folders that are not to be backed up
41
- wanted = backup_folders.map(&:name)
42
- local_folders do |serializer, _folder|
43
- serializer.delete if !wanted.include?(serializer.folder)
44
- end
45
- end
46
- each_folder do |folder, serializer|
47
- begin
48
- next if !folder.exist?
49
- rescue Encoding::UndefinedConversionError
50
- message = "Skipping backup for '#{folder.name}' " \
51
- "as it is not UTF-7 encoded correctly"
52
- Logger.logger.info message
53
- next
54
- end
55
-
56
- Logger.logger.debug "[#{folder.name}] running backup"
57
- serializer.apply_uid_validity(folder.uid_validity)
58
- begin
59
- Downloader.new(
60
- folder,
61
- serializer,
62
- multi_fetch_size: account.multi_fetch_size,
63
- reset_seen_flags_after_fetch: account.reset_seen_flags_after_fetch
64
- ).run
65
- if account.mirror_mode
66
- Logger.logger.info "Mirror mode - Deleting messages only present locally"
67
- LocalOnlyMessageDeleter.new(folder, serializer).run
68
- end
69
- FlagRefresher.new(folder, serializer).run if account.mirror_mode || refresh
70
- rescue Net::IMAP::ByeResponseError
71
- reconnect
72
- retry
73
- end
74
- end
75
- end
76
-
77
- def local_folders
78
- return enum_for(:local_folders) if !block_given?
79
-
80
- ensure_account_folder
81
- glob = File.join(account.local_path, "**", "*.imap")
82
- base = Pathname.new(account.local_path)
83
- Pathname.glob(glob) do |path|
84
- name = path.relative_path_from(base).to_s[0..-6]
85
- serializer = Serializer.new(account.local_path, name)
86
- folder = Account::Folder.new(self, name)
87
- yield serializer, folder
88
- end
89
- end
90
-
91
- def restore
92
- local_folders do |serializer, folder|
93
- Uploader.new(folder, serializer).run
94
- end
95
- end
96
-
97
- def disconnect
98
- client.disconnect if @client
99
- reset
100
- end
101
-
102
- def reconnect
103
- disconnect
104
- end
105
-
106
- def reset
107
- @backup_folders = nil
108
- @client = nil
109
- @folder_names = nil
110
- end
111
-
112
- # TODO: make this private
113
- def client
114
- @client ||= Account::Connection::ClientFactory.new(account: account).run
115
- end
116
-
117
- private
118
-
119
- def each_folder
120
- backup_folders.each do |folder|
121
- serializer = Serializer.new(account.local_path, folder.name)
122
- yield folder, serializer
123
- end
124
- end
125
-
126
- def ensure_account_folder
127
- raise "The backup path for #{account.username} is not set" if !account.local_path
128
-
129
- Utils.make_folder(
130
- File.dirname(account.local_path),
131
- File.basename(account.local_path),
132
- Serializer::Directory::DIRECTORY_PERMISSIONS
133
- )
134
- end
135
- end
136
- end
@@ -1,40 +0,0 @@
1
- require "fileutils"
2
-
3
- module Imap::Backup
4
- module Utils
5
- def self.check_permissions(filename, limit)
6
- actual = mode(filename)
7
- return nil if actual.nil?
8
-
9
- mask = ~limit & 0o777
10
- return if (actual & mask).zero?
11
-
12
- message = format(
13
- "Permissions on '%<filename>s' " \
14
- "should be 0%<limit>o, not 0%<actual>o",
15
- filename: filename, limit: limit, actual: actual
16
- )
17
- raise message
18
- end
19
-
20
- def self.mode(filename)
21
- return nil if !File.exist?(filename)
22
-
23
- stat = File.stat(filename)
24
- stat.mode & 0o777
25
- end
26
-
27
- def self.make_folder(base_path, path, permissions)
28
- parts = path.split("/")
29
- return if parts.empty?
30
-
31
- full_path = File.join(base_path, path)
32
- FileUtils.mkdir_p full_path
33
- path = base_path
34
- parts.each do |part|
35
- path = File.join(path, part)
36
- FileUtils.chmod permissions, path
37
- end
38
- end
39
- end
40
- end