imap-backup 9.4.0.pre1 → 10.0.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.
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