imap-backup 14.4.4 → 14.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -137
  3. data/docs/documentation.md +19 -0
  4. data/lib/imap/backup/account/backup.rb +2 -0
  5. data/lib/imap/backup/account/backup_folders.rb +7 -1
  6. data/lib/imap/backup/account/client_factory.rb +1 -0
  7. data/lib/imap/backup/account/folder.rb +26 -0
  8. data/lib/imap/backup/account/folder_backup.rb +4 -1
  9. data/lib/imap/backup/account/folder_ensurer.rb +3 -0
  10. data/lib/imap/backup/account/local_only_folder_deleter.rb +2 -0
  11. data/lib/imap/backup/account/restore.rb +2 -0
  12. data/lib/imap/backup/account/serialized_folders.rb +5 -1
  13. data/lib/imap/backup/account.rb +15 -11
  14. data/lib/imap/backup/cli/backup.rb +3 -0
  15. data/lib/imap/backup/cli/folder_enumerator.rb +6 -0
  16. data/lib/imap/backup/cli/helpers.rb +13 -0
  17. data/lib/imap/backup/cli/local/check.rb +3 -0
  18. data/lib/imap/backup/cli/local.rb +13 -0
  19. data/lib/imap/backup/cli/remote.rb +7 -0
  20. data/lib/imap/backup/cli/restore.rb +4 -0
  21. data/lib/imap/backup/cli/setup.rb +3 -0
  22. data/lib/imap/backup/cli/single/backup.rb +3 -0
  23. data/lib/imap/backup/cli/single.rb +4 -0
  24. data/lib/imap/backup/cli/stats.rb +3 -0
  25. data/lib/imap/backup/cli/transfer.rb +8 -0
  26. data/lib/imap/backup/cli/utils.rb +6 -0
  27. data/lib/imap/backup/cli.rb +8 -0
  28. data/lib/imap/backup/client/apple_mail.rb +2 -0
  29. data/lib/imap/backup/client/automatic_login_wrapper.rb +9 -1
  30. data/lib/imap/backup/client/default.rb +15 -4
  31. data/lib/imap/backup/configuration.rb +13 -0
  32. data/lib/imap/backup/configuration_not_found.rb +1 -0
  33. data/lib/imap/backup/downloader.rb +4 -0
  34. data/lib/imap/backup/email/mboxrd/message.rb +14 -0
  35. data/lib/imap/backup/email/provider/apple_mail.rb +2 -0
  36. data/lib/imap/backup/email/provider/base.rb +2 -0
  37. data/lib/imap/backup/email/provider/fastmail.rb +2 -0
  38. data/lib/imap/backup/email/provider/gmail.rb +2 -0
  39. data/lib/imap/backup/email/provider/purelymail.rb +2 -0
  40. data/lib/imap/backup/email/provider/unknown.rb +2 -6
  41. data/lib/imap/backup/email/provider.rb +5 -0
  42. data/lib/imap/backup/file_mode.rb +2 -0
  43. data/lib/imap/backup/flag_refresher.rb +4 -0
  44. data/lib/imap/backup/local_only_message_deleter.rb +2 -0
  45. data/lib/imap/backup/logger.rb +18 -0
  46. data/lib/imap/backup/migrator.rb +3 -0
  47. data/lib/imap/backup/mirror/map.rb +21 -0
  48. data/lib/imap/backup/mirror.rb +8 -0
  49. data/lib/imap/backup/naming.rb +10 -1
  50. data/lib/imap/backup/retry_on_error.rb +9 -0
  51. data/lib/imap/backup/serializer/appender.rb +9 -0
  52. data/lib/imap/backup/serializer/delayed_metadata_serializer.rb +4 -0
  53. data/lib/imap/backup/serializer/folder_maker.rb +1 -0
  54. data/lib/imap/backup/serializer/imap.rb +38 -2
  55. data/lib/imap/backup/serializer/integrity_checker.rb +1 -0
  56. data/lib/imap/backup/serializer/mbox.rb +26 -0
  57. data/lib/imap/backup/serializer/message.rb +13 -0
  58. data/lib/imap/backup/serializer/message_enumerator.rb +10 -2
  59. data/lib/imap/backup/serializer/permission_checker.rb +6 -0
  60. data/lib/imap/backup/serializer/transaction.rb +18 -0
  61. data/lib/imap/backup/serializer/unused_name_finder.rb +4 -0
  62. data/lib/imap/backup/serializer/version2_migrator.rb +4 -0
  63. data/lib/imap/backup/serializer.rb +56 -2
  64. data/lib/imap/backup/setup/account/header.rb +6 -0
  65. data/lib/imap/backup/setup/account.rb +6 -0
  66. data/lib/imap/backup/setup/asker.rb +16 -0
  67. data/lib/imap/backup/setup/backup_path.rb +6 -0
  68. data/lib/imap/backup/setup/connection_tester.rb +5 -0
  69. data/lib/imap/backup/setup/email_changer.rb +6 -0
  70. data/lib/imap/backup/setup/folder_chooser.rb +4 -0
  71. data/lib/imap/backup/setup/global_options/download_strategy_chooser.rb +4 -0
  72. data/lib/imap/backup/setup/global_options.rb +4 -0
  73. data/lib/imap/backup/setup/helpers.rb +3 -0
  74. data/lib/imap/backup/setup.rb +5 -0
  75. data/lib/imap/backup/text/sanitizer.rb +9 -0
  76. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +7 -0
  77. data/lib/imap/backup/uploader.rb +5 -0
  78. data/lib/imap/backup/version.rb +6 -1
  79. metadata +3 -5
  80. data/docs/api.md +0 -20
  81. data/docs/development.md +0 -110
  82. data/docs/migrate-server-keep-address.md +0 -47
@@ -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
 
@@ -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
@@ -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
 
@@ -9,15 +9,21 @@ require "imap/backup/serializer/permission_checker"
9
9
  module Imap; end
10
10
 
11
11
  module Imap::Backup
12
+ # Handles the application's configuration file
12
13
  class Configuration
14
+ # The default directory of the configuration file
13
15
  CONFIGURATION_DIRECTORY = File.expand_path("~/.imap-backup")
16
+ # The default download strategy key
14
17
  DEFAULT_STRATEGY = "delay_metadata".freeze
18
+ # The available download strategies
15
19
  DOWNLOAD_STRATEGIES = [
16
20
  {key: "direct", description: "write straight to disk"},
17
21
  {key: DEFAULT_STRATEGY, description: "delay writing metadata"}
18
22
  ].freeze
23
+ # The current file version
19
24
  VERSION = "2.2".freeze
20
25
 
26
+ # @return [String] the default configuration file path
21
27
  def self.default_pathname
22
28
  File.join(CONFIGURATION_DIRECTORY, "config.json")
23
29
  end
@@ -33,10 +39,13 @@ module Imap::Backup
33
39
  @download_strategy_modified = false
34
40
  end
35
41
 
42
+ # @return [String] the directory containing the configuration file
36
43
  def path
37
44
  File.dirname(pathname)
38
45
  end
39
46
 
47
+ # Saves the configuration file in JSON format
48
+ # @return [void]
40
49
  def save
41
50
  ensure_loaded!
42
51
  FileUtils.mkdir_p(path) if !File.directory?(path)
@@ -53,6 +62,7 @@ module Imap::Backup
53
62
  @data = nil
54
63
  end
55
64
 
65
+ # @return [Array<Account>] the configured accounts
56
66
  def accounts
57
67
  @accounts ||= begin
58
68
  ensure_loaded!
@@ -63,12 +73,15 @@ module Imap::Backup
63
73
  end
64
74
  end
65
75
 
76
+ # @return [String] the cofigured download strategy
66
77
  def download_strategy
67
78
  ensure_loaded!
68
79
 
69
80
  @download_strategy
70
81
  end
71
82
 
83
+ # @param value [String] the new strategy
84
+ # @return [void]
72
85
  def download_strategy=(value)
73
86
  raise "Unknown strategy '#{value}'" if !DOWNLOAD_STRATEGIES.find { |s| s[:key] == value }
74
87
 
@@ -1,5 +1,6 @@
1
1
  module Imap; end
2
2
 
3
3
  module Imap::Backup
4
+ # Thrown when no configuration file is found
4
5
  class ConfigurationNotFound < StandardError; end
5
6
  end
@@ -3,7 +3,9 @@ require "net/imap"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Downloads as yet undownloaded emails from an account's server
6
7
  class Downloader
8
+ # @private
7
9
  class MultiFetchFailedError < StandardError; end
8
10
 
9
11
  def initialize(folder, serializer, multi_fetch_size: 1, reset_seen_flags_after_fetch: false)
@@ -14,6 +16,8 @@ module Imap::Backup
14
16
  @uids = nil
15
17
  end
16
18
 
19
+ # Runs the downloader
20
+ # @return [void]
17
21
  def run
18
22
  info("#{uids.count} new messages") if uids.any?
19
23
 
@@ -6,7 +6,13 @@ module Imap::Backup
6
6
  module Email; end
7
7
 
8
8
  module Email::Mboxrd
9
+ # Handles serialization and deserialization of messages
9
10
  class Message
11
+ # @param serialized [String] an email message
12
+ #
13
+ # @return [String] The message without the initial 'From ' line
14
+ # and with one level of '>' quoting removed from other lines
15
+ # that start with 'From'
10
16
  def self.clean_serialized(serialized)
11
17
  cleaned = serialized.gsub(/^>(>*From)/, "\\1")
12
18
  # Serialized messages in this format *should* start with a line
@@ -19,32 +25,40 @@ module Imap::Backup
19
25
  cleaned
20
26
  end
21
27
 
28
+ # @param serialized [String] the on-disk version of the message
29
+ #
30
+ # @return [Message] the original message
22
31
  def self.from_serialized(serialized)
23
32
  new(clean_serialized(serialized))
24
33
  end
25
34
 
35
+ # @return [String] the original message body
26
36
  attr_reader :supplied_body
27
37
 
28
38
  def initialize(supplied_body)
29
39
  @supplied_body = supplied_body.clone
30
40
  end
31
41
 
42
+ # @return [String] the message with an initial 'From ADDRESS' line
32
43
  def to_serialized
33
44
  from_line = "From #{from}\n"
34
45
  body = mboxrd_body.dup.force_encoding(Encoding::UTF_8)
35
46
  from_line + body
36
47
  end
37
48
 
49
+ # @return [Date, nil] the date of the message
38
50
  def date
39
51
  parsed.date
40
52
  rescue StandardError
41
53
  nil
42
54
  end
43
55
 
56
+ # @return [String] the message's subject line
44
57
  def subject
45
58
  parsed.subject
46
59
  end
47
60
 
61
+ # @return [String] the original message ready for transmission to an IMAP server
48
62
  def imap_body
49
63
  supplied_body.gsub(/(?<!\r)\n/, "\r\n")
50
64
  end
@@ -3,7 +3,9 @@ require "imap/backup/email/provider/base"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Provides overrides for Apple mail accounts
6
7
  class Email::Provider::AppleMail < Email::Provider::Base
8
+ # @return [String] the Apple Mail IMAP server host name
7
9
  def host
8
10
  "imap.mail.me.com"
9
11
  end
@@ -4,7 +4,9 @@ module Imap::Backup
4
4
  module Email; end
5
5
  class Email::Provider; end
6
6
 
7
+ # Supplies defaults for email provider behaviour
7
8
  class Email::Provider::Base
9
+ # @return [Hash] defaults for the Net::IMAP connection
8
10
  def options
9
11
  # rubocop:disable Naming/VariableNumber
10
12
  {port: 993, ssl: {ssl_version: :TLSv1_2}}
@@ -3,7 +3,9 @@ require "imap/backup/email/provider/base"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Provides overrides for Fastmail accounts
6
7
  class Email::Provider::Fastmail < Email::Provider::Base
8
+ # @return [String] the Fastmail IMAP server host name
7
9
  def host
8
10
  "imap.fastmail.com"
9
11
  end
@@ -3,7 +3,9 @@ require "imap/backup/email/provider/base"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Provides overrides for GMail accounts
6
7
  class Email::Provider::GMail < Email::Provider::Base
8
+ # @return [String] the GMail IMAP server host name
7
9
  def host
8
10
  "imap.gmail.com"
9
11
  end
@@ -3,7 +3,9 @@ require "imap/backup/email/provider/base"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Provides overrides for Purelymail accounts
6
7
  class Email::Provider::Purelymail < Email::Provider::Base
8
+ # @return [String] The Purelymail IMAP server host name
7
9
  def host
8
10
  "mailserver.purelymail.com"
9
11
  end