imap-backup 14.4.4 → 14.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -137
  3. data/docs/documentation.md +19 -0
  4. data/imap-backup.gemspec +1 -1
  5. data/lib/imap/backup/account/backup.rb +2 -0
  6. data/lib/imap/backup/account/backup_folders.rb +7 -1
  7. data/lib/imap/backup/account/client_factory.rb +1 -0
  8. data/lib/imap/backup/account/folder.rb +26 -0
  9. data/lib/imap/backup/account/folder_backup.rb +4 -1
  10. data/lib/imap/backup/account/folder_ensurer.rb +3 -0
  11. data/lib/imap/backup/account/local_only_folder_deleter.rb +3 -1
  12. data/lib/imap/backup/account/restore.rb +2 -0
  13. data/lib/imap/backup/account/serialized_folders.rb +31 -1
  14. data/lib/imap/backup/account.rb +34 -18
  15. data/lib/imap/backup/cli/backup.rb +3 -0
  16. data/lib/imap/backup/cli/folder_enumerator.rb +6 -0
  17. data/lib/imap/backup/cli/helpers.rb +13 -0
  18. data/lib/imap/backup/cli/local/check.rb +3 -0
  19. data/lib/imap/backup/cli/local.rb +14 -1
  20. data/lib/imap/backup/cli/remote.rb +7 -0
  21. data/lib/imap/backup/cli/restore.rb +4 -0
  22. data/lib/imap/backup/cli/setup.rb +3 -0
  23. data/lib/imap/backup/cli/single/backup.rb +3 -0
  24. data/lib/imap/backup/cli/single.rb +4 -0
  25. data/lib/imap/backup/cli/stats.rb +3 -0
  26. data/lib/imap/backup/cli/transfer.rb +8 -0
  27. data/lib/imap/backup/cli/utils.rb +7 -1
  28. data/lib/imap/backup/cli.rb +8 -0
  29. data/lib/imap/backup/client/apple_mail.rb +2 -0
  30. data/lib/imap/backup/client/automatic_login_wrapper.rb +9 -1
  31. data/lib/imap/backup/client/default.rb +15 -4
  32. data/lib/imap/backup/configuration.rb +13 -0
  33. data/lib/imap/backup/configuration_not_found.rb +1 -0
  34. data/lib/imap/backup/downloader.rb +4 -0
  35. data/lib/imap/backup/email/mboxrd/message.rb +14 -0
  36. data/lib/imap/backup/email/provider/apple_mail.rb +2 -0
  37. data/lib/imap/backup/email/provider/base.rb +3 -3
  38. data/lib/imap/backup/email/provider/fastmail.rb +2 -0
  39. data/lib/imap/backup/email/provider/gmail.rb +2 -0
  40. data/lib/imap/backup/email/provider/purelymail.rb +2 -0
  41. data/lib/imap/backup/email/provider/unknown.rb +2 -6
  42. data/lib/imap/backup/email/provider.rb +5 -0
  43. data/lib/imap/backup/file_mode.rb +2 -0
  44. data/lib/imap/backup/flag_refresher.rb +4 -0
  45. data/lib/imap/backup/local_only_message_deleter.rb +2 -0
  46. data/lib/imap/backup/logger.rb +18 -0
  47. data/lib/imap/backup/migrator.rb +3 -0
  48. data/lib/imap/backup/mirror/map.rb +21 -0
  49. data/lib/imap/backup/mirror.rb +8 -0
  50. data/lib/imap/backup/naming.rb +10 -1
  51. data/lib/imap/backup/retry_on_error.rb +9 -0
  52. data/lib/imap/backup/serializer/appender.rb +9 -0
  53. data/lib/imap/backup/serializer/delayed_metadata_serializer.rb +4 -0
  54. data/lib/imap/backup/serializer/folder_maker.rb +1 -0
  55. data/lib/imap/backup/serializer/imap.rb +38 -2
  56. data/lib/imap/backup/serializer/integrity_checker.rb +1 -0
  57. data/lib/imap/backup/serializer/mbox.rb +26 -0
  58. data/lib/imap/backup/serializer/message.rb +13 -0
  59. data/lib/imap/backup/serializer/message_enumerator.rb +10 -2
  60. data/lib/imap/backup/serializer/permission_checker.rb +6 -0
  61. data/lib/imap/backup/serializer/transaction.rb +18 -0
  62. data/lib/imap/backup/serializer/unused_name_finder.rb +4 -0
  63. data/lib/imap/backup/serializer/version2_migrator.rb +4 -0
  64. data/lib/imap/backup/serializer.rb +56 -2
  65. data/lib/imap/backup/setup/account/header.rb +6 -0
  66. data/lib/imap/backup/setup/account.rb +6 -0
  67. data/lib/imap/backup/setup/asker.rb +16 -0
  68. data/lib/imap/backup/setup/backup_path.rb +6 -0
  69. data/lib/imap/backup/setup/connection_tester.rb +5 -0
  70. data/lib/imap/backup/setup/email_changer.rb +6 -0
  71. data/lib/imap/backup/setup/folder_chooser.rb +4 -0
  72. data/lib/imap/backup/setup/global_options/download_strategy_chooser.rb +4 -0
  73. data/lib/imap/backup/setup/global_options.rb +4 -0
  74. data/lib/imap/backup/setup/helpers.rb +3 -0
  75. data/lib/imap/backup/setup.rb +5 -0
  76. data/lib/imap/backup/text/sanitizer.rb +9 -0
  77. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +8 -1
  78. data/lib/imap/backup/uploader.rb +5 -0
  79. data/lib/imap/backup/version.rb +7 -2
  80. metadata +11 -13
  81. data/docs/api.md +0 -20
  82. data/docs/development.md +0 -110
  83. data/docs/migrate-server-keep-address.md +0 -47
@@ -14,10 +14,9 @@ module Imap::Backup
14
14
  # The username of the account (usually the same as the email address)
15
15
  # @return [String]
16
16
  attr_reader :username
17
- # The password of the Account
17
+ # @return [String] password of the Account
18
18
  attr_reader :password
19
- # The path where backups will be saved
20
- # @return [String]
19
+ # @return [String] the path where backups will be saved
21
20
  attr_reader :local_path
22
21
  # @overload folders
23
22
  # The list of folders that have been configured for the Account
@@ -38,13 +37,11 @@ module Imap::Backup
38
37
  attr_reader :folder_blacklist
39
38
  # Should all emails be backed up progressively, or should emails
40
39
  # which are deleted from the server be deleted locally?
40
+ # @return [Boolean]
41
41
  attr_reader :mirror_mode
42
42
  # The address of the IMAP server
43
43
  # @return [String]
44
44
  attr_reader :server
45
- # Extra options to be passed to the IMAP server when connecting
46
- # @return [Hash, void]
47
- attr_reader :connection_options
48
45
  # The name of the download strategy to adopt during backups
49
46
  # @return [String]
50
47
  attr_accessor :download_strategy
@@ -61,18 +58,17 @@ module Imap::Backup
61
58
  # mark messages as '\Seen' when accessed).
62
59
  # @return [Boolean]
63
60
  attr_reader :reset_seen_flags_after_fetch
64
- # Tracks changes to the Account's attributes
65
- attr_reader :changes
66
61
 
67
62
  def initialize(options)
68
63
  @username = options[:username]
69
64
  @password = options[:password]
70
65
  @local_path = options[:local_path]
71
66
  @folders = options[:folders]
72
- @folder_blacklist = options[:folder_blacklist]
73
- @mirror_mode = options[:mirror_mode]
67
+ @folder_blacklist = options[:folder_blacklist] || false
68
+ @mirror_mode = options[:mirror_mode] || false
74
69
  @server = options[:server]
75
- @connection_options = options[:connection_options]
70
+ @connection_options = nil
71
+ @supplied_connection_options = options[:connection_options]
76
72
  @download_strategy = options[:download_strategy]
77
73
  @multi_fetch_size_orignal = options[:multi_fetch_size]
78
74
  @reset_seen_flags_after_fetch = options[:reset_seen_flags_after_fetch]
@@ -123,6 +119,7 @@ module Imap::Backup
123
119
  end
124
120
 
125
121
  # Resets the store of changes, indicating that the current state is the saved state
122
+ # @return [void]
126
123
  def clear_changes
127
124
  @changes = {}
128
125
  end
@@ -134,16 +131,12 @@ module Imap::Backup
134
131
  @marked_for_deletion = true
135
132
  end
136
133
 
137
- # Indicates whether the account has been flagged for deletion during setup
138
- #
139
- # @return [Boolean]
134
+ # @return [Boolean] whether the account has been flagged for deletion during setup
140
135
  def marked_for_deletion?
141
136
  @marked_for_deletion
142
137
  end
143
138
 
144
- # Returns all Account data for serialization
145
- #
146
- # @return [Hash]
139
+ # @return [Hash] all Account data for serialization
147
140
  def to_h
148
141
  h = {username: @username, password: @password}
149
142
  h[:local_path] = @local_path if @local_path
@@ -151,7 +144,7 @@ module Imap::Backup
151
144
  h[:folder_blacklist] = true if @folder_blacklist
152
145
  h[:mirror_mode] = true if @mirror_mode
153
146
  h[:server] = @server if @server
154
- h[:connection_options] = @connection_options if @connection_options
147
+ h[:connection_options] = @connection_options if connection_options
155
148
  h[:multi_fetch_size] = multi_fetch_size
156
149
  if @reset_seen_flags_after_fetch
157
150
  h[:reset_seen_flags_after_fetch] = @reset_seen_flags_after_fetch
@@ -180,25 +173,45 @@ module Imap::Backup
180
173
  update(:local_path, value)
181
174
  end
182
175
 
176
+ # @raise [RuntimeError] if the supplied value is not an Array
177
+ # @return [void]
183
178
  def folders=(value)
184
179
  raise "folders must be an Array" if !value.is_a?(Array)
185
180
 
186
181
  update(:folders, value)
187
182
  end
188
183
 
184
+ # @return [void]
189
185
  def folder_blacklist=(value)
190
186
  update(:folder_blacklist, value)
191
187
  end
192
188
 
189
+ # @return [void]
193
190
  def mirror_mode=(value)
194
191
  update(:mirror_mode, value)
195
192
  end
196
193
 
194
+ # @return [void]
197
195
  def server=(value)
198
196
  update(:server, value)
199
197
  end
200
198
 
199
+ # Extra options to be passed to the IMAP server when connecting
200
+ # @return [Hash, void]
201
+ def connection_options
202
+ @connection_options ||=
203
+ case @supplied_connection_options
204
+ when String
205
+ JSON.parse(@supplied_connection_options, symbolize_names: true)
206
+ else
207
+ @supplied_connection_options
208
+ end
209
+ end
210
+
211
+ # @return [void]
201
212
  def connection_options=(value)
213
+ # Ensure we've loaded the connection_options
214
+ connection_options
202
215
  parsed =
203
216
  if value == ""
204
217
  nil
@@ -232,12 +245,15 @@ module Imap::Backup
232
245
  update(:multi_fetch_size, parsed)
233
246
  end
234
247
 
248
+ # @return [void]
235
249
  def reset_seen_flags_after_fetch=(value)
236
250
  update(:reset_seen_flags_after_fetch, value)
237
251
  end
238
252
 
239
253
  private
240
254
 
255
+ attr_reader :changes
256
+
241
257
  def update(field, value)
242
258
  key = :"@#{field}"
243
259
  if changes[field]
@@ -10,6 +10,7 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class CLI < Thor; end
12
12
 
13
+ # Runs backups of configured accounts
13
14
  class CLI::Backup < Thor
14
15
  include Thor::Actions
15
16
  include CLI::Helpers
@@ -19,6 +20,8 @@ module Imap::Backup
19
20
  @options = options
20
21
  end
21
22
 
23
+ # @!method run
24
+ # @return [void]
22
25
  no_commands do
23
26
  def run
24
27
  config = load_config(**options)
@@ -9,6 +9,7 @@ module Imap; end
9
9
  module Imap::Backup
10
10
  class CLI < Thor; end
11
11
 
12
+ # Implements a folder enumerator for backed-up accounts
12
13
  class CLI::FolderEnumerator
13
14
  def initialize(
14
15
  destination:,
@@ -26,6 +27,11 @@ module Imap::Backup
26
27
  @source_prefix = source_prefix
27
28
  end
28
29
 
30
+ # Enumerates backed-up folders
31
+ # When called without a block, returns an Enumerator
32
+ # @yieldparam serializer [Serializer] the folder's serializer
33
+ # @yieldparam folder [Account::Folder] the online folder
34
+ # @return [Enumerator, void]
29
35
  def each
30
36
  return enum_for(:each) if !block_given?
31
37
 
@@ -8,6 +8,7 @@ module Imap; end
8
8
  module Imap::Backup
9
9
  class CLI < Thor; end
10
10
 
11
+ # Provides helper methods for CLI classes
11
12
  module CLI::Helpers
12
13
  def self.included(base)
13
14
  base.class_eval do
@@ -73,6 +74,10 @@ module Imap::Backup
73
74
  end
74
75
  end
75
76
 
77
+ # Processes command-line parameters
78
+ # @return [Hash] the supplied command-line parameters with
79
+ # with hyphens in keys replaced by underscores
80
+ # and the keys converted to Symbols
76
81
  def options
77
82
  @symbolized_options ||= # rubocop:disable Naming/MemoizedInstanceVariableName
78
83
  begin
@@ -89,6 +94,9 @@ module Imap::Backup
89
94
  end
90
95
  end
91
96
 
97
+ # Loads the application configuration
98
+ # @raise [ConfigurationNotFound] if the configuration file does not exist
99
+ # @return [Configuration]
92
100
  def load_config(**options)
93
101
  path = options[:config]
94
102
  require_exists = options.key?(:require_exists) ? options[:require_exists] : true
@@ -102,6 +110,8 @@ module Imap::Backup
102
110
  Configuration.new(path: path)
103
111
  end
104
112
 
113
+ # @raise [RuntimeError] if the account does not exist
114
+ # @return [Account] the Account information for the email address
105
115
  def account(config, email)
106
116
  account = config.accounts.find { |a| a.username == email }
107
117
  raise "#{email} is not a configured account" if !account
@@ -109,6 +119,9 @@ module Imap::Backup
109
119
  account
110
120
  end
111
121
 
122
+ # @return [Array<Account>] If email addresses have been specified
123
+ # returns the Account configurations for them.
124
+ # If non have been specified, returns all account configurations
112
125
  def requested_accounts(config)
113
126
  emails = (options[:accounts] || "").split(",")
114
127
  if emails.any?
@@ -10,6 +10,7 @@ module Imap::Backup
10
10
  class CLI; end
11
11
  class CLI::Local < Thor; end
12
12
 
13
+ # Runs integrity check on local backups
13
14
  class CLI::Local::Check
14
15
  include CLI::Helpers
15
16
 
@@ -17,6 +18,8 @@ module Imap::Backup
17
18
  @options = options
18
19
  end
19
20
 
21
+ # Runs the check
22
+ # @return [void]
20
23
  def run
21
24
  results = requested_accounts(config).map do |account|
22
25
  serialized_folders = Account::SerializedFolders.new(account: account)
@@ -10,6 +10,7 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class CLI < Thor; end
12
12
 
13
+ # Implements the CLI functions relating to local storage
13
14
  class CLI::Local < Thor
14
15
  include Thor::Actions
15
16
  include CLI::Helpers
@@ -19,6 +20,8 @@ module Imap::Backup
19
20
  format_option
20
21
  quiet_option
21
22
  verbose_option
23
+ # Lists configured accounts
24
+ # @return [void]
22
25
  def accounts
23
26
  names = config.accounts.map(&:username)
24
27
  case options[:format]
@@ -44,6 +47,8 @@ module Imap::Backup
44
47
  format_option
45
48
  quiet_option
46
49
  verbose_option
50
+ # Runs integrity checks on backups
51
+ # @return [void]
47
52
  def check
48
53
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
49
54
  Check.new(non_logging_options).run
@@ -54,6 +59,8 @@ module Imap::Backup
54
59
  format_option
55
60
  quiet_option
56
61
  verbose_option
62
+ # Lists backed-up folders for an account
63
+ # @return [void]
57
64
  def folders(email)
58
65
  account = account(config, email)
59
66
 
@@ -63,7 +70,7 @@ module Imap::Backup
63
70
  list = serialized_folders.map { |_s, f| {name: f.name} }
64
71
  Kernel.puts list.to_json
65
72
  else
66
- serialized_folders.each do |_s, f|
73
+ serialized_folders.each_value do |f|
67
74
  Kernel.puts %("#{f.name}")
68
75
  end
69
76
  end
@@ -74,6 +81,9 @@ module Imap::Backup
74
81
  format_option
75
82
  quiet_option
76
83
  verbose_option
84
+ # Lists backed-up emails for an account folder
85
+ # @raise [RuntimeError] if the folder does not exist
86
+ # @return [void]
77
87
  def list(email, folder_name)
78
88
  account = account(config, email)
79
89
 
@@ -101,6 +111,9 @@ module Imap::Backup
101
111
  format_option
102
112
  quiet_option
103
113
  verbose_option
114
+ # Shows the content of one or more backed-up email messages
115
+ # @raise [RuntimeError] if the folder does not exist
116
+ # @return [void]
104
117
  def show(email, folder_name, uids)
105
118
  account = account(config, email)
106
119
 
@@ -8,6 +8,7 @@ module Imap; end
8
8
  module Imap::Backup
9
9
  class CLI < Thor; end
10
10
 
11
+ # Implements the CLI functions relating to configured online accounts
11
12
  class CLI::Remote < Thor
12
13
  include Thor::Actions
13
14
  include CLI::Helpers
@@ -17,6 +18,8 @@ module Imap::Backup
17
18
  format_option
18
19
  quiet_option
19
20
  verbose_option
21
+ # Prints an account's folders
22
+ # @return [void]
20
23
  def folders(email)
21
24
  Imap::Backup::Logger.setup_logging options
22
25
  folder_names = folder_names(email)
@@ -36,6 +39,8 @@ module Imap::Backup
36
39
  format_option
37
40
  quiet_option
38
41
  verbose_option
42
+ # Prints an account's IMAP capabilities
43
+ # @return [void]
39
44
  def capabilities(email)
40
45
  Imap::Backup::Logger.setup_logging options
41
46
  config = load_config(**options)
@@ -55,6 +60,8 @@ module Imap::Backup
55
60
  format_option
56
61
  quiet_option
57
62
  verbose_option
63
+ # Prints an account's IMAP namespaces
64
+ # @return [void]
58
65
  def namespaces(email)
59
66
  Imap::Backup::Logger.setup_logging options
60
67
  config = load_config(**options)
@@ -8,6 +8,7 @@ module Imap; end
8
8
  module Imap::Backup
9
9
  class CLI < Thor; end
10
10
 
11
+ # Restores backups for one or more accounts
11
12
  class CLI::Restore < Thor
12
13
  include Thor::Actions
13
14
  include CLI::Helpers
@@ -18,6 +19,9 @@ module Imap::Backup
18
19
  @options = options
19
20
  end
20
21
 
22
+ # @!method run
23
+ # @raise [RuntimeError] if no email is specified
24
+ # @return [void]
21
25
  no_commands do
22
26
  def run
23
27
  config = load_config(**options)
@@ -8,6 +8,7 @@ module Imap; end
8
8
  module Imap::Backup
9
9
  class CLI < Thor; end
10
10
 
11
+ # Runs the menu-driven setup program
11
12
  class CLI::Setup < Thor
12
13
  include Thor::Actions
13
14
  include CLI::Helpers
@@ -17,6 +18,8 @@ module Imap::Backup
17
18
  @options = options
18
19
  end
19
20
 
21
+ # @!method run
22
+ # @return [void]
20
23
  no_commands do
21
24
  def run
22
25
  config = load_config(**options, require_exists: false)
@@ -10,12 +10,15 @@ module Imap::Backup
10
10
  class CLI < Thor; end
11
11
  class CLI::Single < Thor; end
12
12
 
13
+ # Runs a backup without relying on existing configuration
13
14
  class CLI::Single::Backup
14
15
  def initialize(options)
15
16
  @options = options
16
17
  @password = nil
17
18
  end
18
19
 
20
+ # Runs the backup
21
+ # @return [void]
19
22
  def run
20
23
  process_options!
21
24
  account = Account.new(
@@ -9,6 +9,8 @@ module Imap; end
9
9
  module Imap::Backup
10
10
  class CLI < Thor; end
11
11
 
12
+ # Processes parameters to run a backup via command-line parameters
13
+ # (without using a configuration file)
12
14
  class CLI::Single < Thor
13
15
  include CLI::Helpers
14
16
 
@@ -170,6 +172,8 @@ module Imap::Backup
170
172
  )
171
173
  quiet_option
172
174
  verbose_option
175
+ # Launches the backup procedure
176
+ # @return [void]
173
177
  def backup
174
178
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
175
179
  direct = Backup.new(non_logging_options)
@@ -4,6 +4,7 @@ require "imap/backup/serializer"
4
4
  module Imap; end
5
5
 
6
6
  module Imap::Backup
7
+ # Prints various statistics about an account and its backup
7
8
  class CLI::Stats < Thor
8
9
  include Thor::Actions
9
10
  include CLI::Helpers
@@ -14,6 +15,8 @@ module Imap::Backup
14
15
  @options = options
15
16
  end
16
17
 
18
+ # @!method run
19
+ # @return [void]
17
20
  no_commands do
18
21
  def run
19
22
  case options[:format]
@@ -8,10 +8,12 @@ require "imap/backup/mirror"
8
8
  module Imap; end
9
9
 
10
10
  module Imap::Backup
11
+ # Implements migration and mirroring
11
12
  class CLI::Transfer < Thor
12
13
  include Thor::Actions
13
14
  include CLI::Helpers
14
15
 
16
+ # The possible vaues for the action parameter
15
17
  ACTIONS = %i(migrate mirror).freeze
16
18
 
17
19
  def initialize(action, source_email, destination_email, options)
@@ -29,6 +31,12 @@ module Imap::Backup
29
31
  @source_prefix = nil
30
32
  end
31
33
 
34
+ # @!method run
35
+ # @raise [RuntimeError] if the indicated action is unknown,
36
+ # or the source and destination accounts are the same,
37
+ # or either of the accounts is not configured,
38
+ # or incompatible namespace/delimter parameters have been supplied
39
+ # @return [void]
32
40
  no_commands do
33
41
  def run
34
42
  raise "Unknown action '#{action}'" if !ACTIONS.include?(action)
@@ -13,6 +13,7 @@ module Imap; end
13
13
  module Imap::Backup
14
14
  class CLI < Thor; end
15
15
 
16
+ # Implements the CLI utility functions
16
17
  class CLI::Utils < Thor
17
18
  include Thor::Actions
18
19
  include CLI::Helpers
@@ -21,6 +22,9 @@ module Imap::Backup
21
22
  config_option
22
23
  quiet_option
23
24
  verbose_option
25
+ # Creates fake downloaded emails so that only the account's future emails
26
+ # will really get backed up
27
+ # @return [void]
24
28
  def ignore_history(email)
25
29
  Logger.setup_logging options
26
30
  config = load_config(**options)
@@ -59,6 +63,8 @@ module Imap::Backup
59
63
  banner: "the name of the Thunderbird profile to copy emails to",
60
64
  aliases: ["-p"]
61
65
  )
66
+ # Exports the account's emails to Thunderbird
67
+ # @return [void]
62
68
  def export_to_thunderbird(email)
63
69
  Imap::Backup::Logger.setup_logging options
64
70
  force = options.key?(:force) ? options[:force] : false
@@ -78,7 +84,7 @@ module Imap::Backup
78
84
 
79
85
  raise "No serialized folders were found for account '#{email}'" if serialized_folders.none?
80
86
 
81
- serialized_folders.each do |serializer, _folder|
87
+ serialized_folders.each_key do |serializer|
82
88
  Thunderbird::MailboxExporter.new(
83
89
  email, serializer, profile, force: force
84
90
  ).run
@@ -48,6 +48,7 @@ module Imap::Backup
48
48
 
49
49
  # Overrides {https://www.rubydoc.info/gems/thor/Thor%2FBase%2FClassMethods:start Thor's method}
50
50
  # to handle '--version' and rearrange parameters if 'help' is passed
51
+ # @return [void]
51
52
  def self.start(args)
52
53
  if args.include?("--version")
53
54
  new.version
@@ -87,6 +88,7 @@ module Imap::Backup
87
88
  refresh_option
88
89
  verbose_option
89
90
  # Runs account backups
91
+ # @return [void]
90
92
  def backup
91
93
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
92
94
  Backup.new(non_logging_options).run
@@ -148,6 +150,7 @@ module Imap::Backup
148
150
  aliases: ["-s"]
149
151
  )
150
152
  # Migrates emails from one account to another
153
+ # @return [void]
151
154
  def migrate(source_email, destination_email)
152
155
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
153
156
  Transfer.new(:migrate, source_email, destination_email, non_logging_options).run
@@ -208,6 +211,7 @@ module Imap::Backup
208
211
  aliases: ["-s"]
209
212
  )
210
213
  # Keeps one email account in line with another
214
+ # @return [void]
211
215
  def mirror(source_email, destination_email)
212
216
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
213
217
  Transfer.new(:mirror, source_email, destination_email, non_logging_options).run
@@ -226,6 +230,7 @@ module Imap::Backup
226
230
  quiet_option
227
231
  verbose_option
228
232
  # Restores backed up meails to an account
233
+ # @return [void]
229
234
  def restore(email = nil)
230
235
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
231
236
  Restore.new(email, non_logging_options).run
@@ -240,6 +245,7 @@ module Imap::Backup
240
245
  quiet_option
241
246
  verbose_option
242
247
  # Runs the menu-driven setup program
248
+ # @return [void]
243
249
  def setup
244
250
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
245
251
  CLI::Setup.new(non_logging_options).run
@@ -264,6 +270,7 @@ module Imap::Backup
264
270
  quiet_option
265
271
  verbose_option
266
272
  # Prints various statistics about a configured account
273
+ # @return [void]
267
274
  def stats(email)
268
275
  non_logging_options = Imap::Backup::Logger.setup_logging(options)
269
276
  Stats.new(email, non_logging_options).run
@@ -274,6 +281,7 @@ module Imap::Backup
274
281
 
275
282
  desc "version", "Print the imap-backup version"
276
283
  # Prints the program version
284
+ # @return [void]
277
285
  def version
278
286
  Kernel.puts "imap-backup #{Imap::Backup::VERSION}"
279
287
  end
@@ -3,9 +3,11 @@ require "imap/backup/client/default"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Overrides default IMAP client behaviour for Apple Mail accounts
6
7
  class Client::AppleMail < Client::Default
7
8
  # With Apple Mails's IMAP, passing "/" to list
8
9
  # results in an empty list
10
+ # @return [String] the value to use when requesting the list of account folders
9
11
  def provider_root
10
12
  ""
11
13
  end
@@ -5,19 +5,24 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  module Client; end
7
7
 
8
+ # Transparently wraps a client instance, while delaying login until it becomes necessary
8
9
  class Client::AutomaticLoginWrapper
9
10
  include RetryOnError
10
11
 
12
+ # @private
11
13
  LOGIN_RETRY_CLASSES = [::EOFError, ::Errno::ECONNRESET, ::SocketError].freeze
12
14
 
15
+ # @return [Client]
13
16
  attr_reader :client
14
- attr_reader :login_called
15
17
 
16
18
  def initialize(client:)
17
19
  @client = client
18
20
  @login_called = false
19
21
  end
20
22
 
23
+ # Proxies calls to the client.
24
+ # Before the first call does login
25
+ # @return the return value of the client method called
21
26
  def method_missing(method_name, *arguments, &block)
22
27
  if login_called
23
28
  client.send(method_name, *arguments, &block)
@@ -27,12 +32,15 @@ module Imap::Backup
27
32
  end
28
33
  end
29
34
 
35
+ # @return [Boolean] whether the client responds to the method
30
36
  def respond_to_missing?(method_name, _include_private = false)
31
37
  client.respond_to?(method_name)
32
38
  end
33
39
 
34
40
  private
35
41
 
42
+ attr_reader :login_called
43
+
36
44
  def do_first_login
37
45
  retry_on_error(errors: LOGIN_RETRY_CLASSES) do
38
46
  client.login
@@ -8,6 +8,8 @@ module Imap; end
8
8
  module Imap::Backup
9
9
  module Client; end
10
10
 
11
+ # Wraps a Net::IMAP instance
12
+ # Tracks the latest folder selection in order to avoid repeated calls
11
13
  class Client::Default
12
14
  extend Forwardable
13
15
  def_delegators :imap, *%i(
@@ -22,6 +24,7 @@ module Imap::Backup
22
24
  @state = nil
23
25
  end
24
26
 
27
+ # @return [Array<String>] the account folders
25
28
  def list
26
29
  root = provider_root
27
30
  mailbox_lists = imap.list(root, "*")
@@ -31,36 +34,44 @@ module Imap::Backup
31
34
  mailbox_lists.map { |ml| extract_name(ml) }
32
35
  end
33
36
 
37
+ # Logs in to the account on the IMAP server
38
+ # @return [void]
34
39
  def login
35
40
  Logger.logger.debug "Logging in: #{account.username}/#{masked_password}"
36
41
  imap.login(account.username, account.password)
37
42
  Logger.logger.debug "Login complete"
38
43
  end
39
44
 
45
+ # Logs out and back in to the server
46
+ # @return [void]
40
47
  def reconnect
41
48
  disconnect
42
49
  login
43
50
  end
44
51
 
52
+ # @return [String] the account username
45
53
  def username
46
54
  account.username
47
55
  end
48
56
 
49
- # Track mailbox selection during delegation to Net::IMAP instance
50
-
57
+ # Disconects from the server
58
+ # @return [void]
51
59
  def disconnect
52
60
  imap.disconnect
53
61
  self.state = nil
54
62
  end
55
63
 
64
+ # Prepares read-only access to a folder
65
+ # @return [void]
56
66
  def examine(mailbox)
57
67
  return if state == [:examine, mailbox]
58
68
 
59
- result = imap.examine(mailbox)
69
+ imap.examine(mailbox)
60
70
  self.state = [:examine, mailbox]
61
- result
62
71
  end
63
72
 
73
+ # Prepares read-write access to a folder
74
+ # @return [void]
64
75
  def select(mailbox)
65
76
  return if state == [:select, mailbox]
66
77