imap-backup 14.4.4 → 14.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -3,14 +3,21 @@ require "imap/backup/serializer/transaction"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Stores messages
6
7
  class Serializer::Mbox
8
+ # @return [String] The path of the mailbox file, without the '.mbox' extension
7
9
  attr_reader :folder_path
8
10
 
11
+ # @param folder_path [String] The path of the mailbox file, without the '.mbox' extension
9
12
  def initialize(folder_path)
10
13
  @folder_path = folder_path
11
14
  @tsx = nil
12
15
  end
13
16
 
17
+ # Starts a transaction
18
+ # @param block [block] the block that is wrapped by the transaction
19
+ # @raise re-raises errors which occur in the block
20
+ # @return [void]
14
21
  def transaction(&block)
15
22
  tsx.fail_in_transaction!(:transaction, message: "nested transactions are not supported")
16
23
 
@@ -26,6 +33,8 @@ module Imap::Backup
26
33
  end
27
34
  end
28
35
 
36
+ # Returns to the pre-transaction state
37
+ # @return [void]
29
38
  def rollback
30
39
  tsx.fail_outside_transaction!(:rollback)
31
40
 
@@ -36,12 +45,19 @@ module Imap::Backup
36
45
  exist?
37
46
  end
38
47
 
48
+ # Serializes a message
49
+ # @param message [String] the message text
50
+ # @return [void]
39
51
  def append(message)
40
52
  File.open(pathname, "ab") do |file|
41
53
  file.write message
42
54
  end
43
55
  end
44
56
 
57
+ # Reads a message from disk
58
+ # @param offset [Integer] the start of the message inside the mailbox file
59
+ # @param length [Integer] the length of the message (as stored on disk)
60
+ # @return [String] the message
45
61
  def read(offset, length)
46
62
  File.open(pathname, "rb") do |f|
47
63
  f.seek offset
@@ -49,6 +65,8 @@ module Imap::Backup
49
65
  end
50
66
  end
51
67
 
68
+ # Deletes the mailbox
69
+ # @return [void]
52
70
  def delete
53
71
  return if !exist?
54
72
 
@@ -59,16 +77,22 @@ module Imap::Backup
59
77
  File.exist?(pathname)
60
78
  end
61
79
 
80
+ # @return [Integer] The lsize of the disk file
62
81
  def length
63
82
  return nil if !exist?
64
83
 
65
84
  File.stat(pathname).size
66
85
  end
67
86
 
87
+ # @return [String] The full path name of the mailbox
68
88
  def pathname
69
89
  "#{folder_path}.mbox"
70
90
  end
71
91
 
92
+ # Renames the mailbox, if it exists,
93
+ # otherwise, simply stores the new name
94
+ # @param new_path [String] the new path (without extension)
95
+ # @return [void]
72
96
  def rename(new_path)
73
97
  if exist?
74
98
  old_pathname = pathname
@@ -79,6 +103,8 @@ module Imap::Backup
79
103
  end
80
104
  end
81
105
 
106
+ # Sets the mailbox file's updated time to the current time
107
+ # @return [void]
82
108
  def touch
83
109
  File.open(pathname, "a") {}
84
110
  end
@@ -5,10 +5,15 @@ require "imap/backup/email/mboxrd/message"
5
5
  module Imap; end
6
6
 
7
7
  module Imap::Backup
8
+ # Represents a stored message
8
9
  class Serializer::Message
10
+ # @return [Array[Symbol]] the message's flags
9
11
  attr_accessor :flags
12
+ # @return [Integer] the length of the message (as stored on disk)
10
13
  attr_reader :length
14
+ # @return [Integer] the start of the message inside the mailbox file
11
15
  attr_reader :offset
16
+ # @return [Integer] the message's UID
12
17
  attr_accessor :uid
13
18
 
14
19
  extend Forwardable
@@ -16,6 +21,11 @@ module Imap::Backup
16
21
  def_delegator :message, :supplied_body, :body
17
22
  def_delegators :message, :imap_body, :date, :subject
18
23
 
24
+ # @param uid [Integer] the message's UID
25
+ # @param offset [Integer] the start of the message inside the mailbox file
26
+ # @param length [Integer] the length of the message (as stored on disk)
27
+ # @param mbox [Serializer::Mbox] the mailbox containing the message
28
+ # @param flags [Array[Symbol]] the message's flags
19
29
  def initialize(uid:, offset:, length:, mbox:, flags: [])
20
30
  @uid = uid
21
31
  @offset = offset
@@ -24,6 +34,7 @@ module Imap::Backup
24
34
  @flags = flags.map(&:to_sym)
25
35
  end
26
36
 
37
+ # @return [Hash] the message metadata
27
38
  def to_h
28
39
  {
29
40
  uid: uid,
@@ -33,6 +44,8 @@ module Imap::Backup
33
44
  }
34
45
  end
35
46
 
47
+ # Reads the message text and returns the original form
48
+ # @return [String] the message
36
49
  def message
37
50
  @message =
38
51
  begin
@@ -1,13 +1,17 @@
1
1
  module Imap; end
2
2
 
3
3
  module Imap::Backup
4
+ # Enumerates over a list of stores messages
4
5
  class Serializer::MessageEnumerator
5
- attr_reader :imap
6
-
6
+ # @param imap [Serializer::Imap] the metadata serializer for the folder
7
7
  def initialize(imap:)
8
8
  @imap = imap
9
9
  end
10
10
 
11
+ # Enumerates over the messages
12
+ # @param uids [Array<Integer>] the message UIDs of the messages to iterate over
13
+ # @yieldparam message [Serializer::Message]
14
+ # @return [void]
11
15
  def run(uids:)
12
16
  uids.each do |uid_maybe_string|
13
17
  uid = uid_maybe_string.to_i
@@ -18,5 +22,9 @@ module Imap::Backup
18
22
  yield message
19
23
  end
20
24
  end
25
+
26
+ private
27
+
28
+ attr_reader :imap
21
29
  end
22
30
  end
@@ -3,12 +3,18 @@ require "imap/backup/file_mode"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Ensures a file has the desired permissions
6
7
  class Serializer::PermissionChecker
8
+ # @param filename [String] the file name
9
+ # @param limit [Integer] the maximum permission that should be set
7
10
  def initialize(filename:, limit:)
8
11
  @filename = filename
9
12
  @limit = limit
10
13
  end
11
14
 
15
+ # Runs the check
16
+ # @raise [RuntimeError] if the permissions are incorrect
17
+ # @return [void]
12
18
  def run
13
19
  actual = FileMode.new(filename: filename).mode
14
20
  return nil if actual.nil?
@@ -1,15 +1,23 @@
1
1
  module Imap; end
2
2
 
3
3
  module Imap::Backup
4
+ # Stores data during a transaction
4
5
  class Serializer::Transaction
6
+ # @return the transaction's stored data
5
7
  attr_reader :data
6
8
 
9
+ # @param owner [any] the class using the transaction -
10
+ # this is used when raising errors
7
11
  def initialize(owner:)
8
12
  @data = nil
9
13
  @owner = owner
10
14
  @in_transaction = false
11
15
  end
12
16
 
17
+ # Runs the transaction
18
+ # @param data [any] the data to maintain during the transaction
19
+ # @param block [block] the block to wrap with the transaction
20
+ # @return [void]
13
21
  def begin(data, &block)
14
22
  @data = data
15
23
  @in_transaction = true
@@ -17,6 +25,8 @@ module Imap::Backup
17
25
  @in_transaction = false
18
26
  end
19
27
 
28
+ # Clears rollback data
29
+ # @return [void]
20
30
  def clear
21
31
  @data = nil
22
32
  end
@@ -25,10 +35,18 @@ module Imap::Backup
25
35
  @in_transaction
26
36
  end
27
37
 
38
+ # Throws an exception if there is a current transaction
39
+ # @param method [Symbol] the method where the check is run
40
+ # @raise [RuntimeError] if called from inside a transaction
41
+ # @return [void]
28
42
  def fail_in_transaction!(method, message: "not supported inside trasactions")
29
43
  raise "#{owner.class}##{method} #{message}" if in_transaction?
30
44
  end
31
45
 
46
+ # Throws an exception if there is not a current transaction
47
+ # @param method [Symbol] the method where the check is run
48
+ # @raise [RuntimeError] if called from outside a transaction
49
+ # @return [void]
32
50
  def fail_outside_transaction!(method)
33
51
  raise "#{owner.class}##{method} can only be called inside a transaction" if !in_transaction?
34
52
  end
@@ -3,11 +3,15 @@ require "imap/backup/serializer"
3
3
  module Imap; end
4
4
 
5
5
  module Imap::Backup
6
+ # Finds a name that can be used to rename a serialized folder
6
7
  class Serializer::UnusedNameFinder
8
+ # @param serializer [Serializer] a folder serializer
7
9
  def initialize(serializer:)
8
10
  @serializer = serializer
9
11
  end
10
12
 
13
+ # Finds the name
14
+ # @return [String] the name
11
15
  def run
12
16
  digit = 0
13
17
  folder = nil
@@ -5,7 +5,9 @@ require "imap/backup/serializer/imap"
5
5
  module Imap; end
6
6
 
7
7
  module Imap::Backup
8
+ # Migrates serialized folder metadata from the version 2 format to the version 3 format
8
9
  class Serializer::Version2Migrator
10
+ # @param folder_path [String] the base pathv(without extension) of the folder backup
9
11
  def initialize(folder_path)
10
12
  @folder_path = folder_path
11
13
  end
@@ -21,6 +23,8 @@ module Imap::Backup
21
23
  true
22
24
  end
23
25
 
26
+ # Runs the migration
27
+ # @return [Boolean] whether the migration was run
24
28
  def run
25
29
  return false if !required?
26
30
 
@@ -15,7 +15,11 @@ require "imap/backup/serializer/unused_name_finder"
15
15
  module Imap; end
16
16
 
17
17
  module Imap::Backup
18
+ # Handles serialization for a folder
18
19
  class Serializer
20
+ # @param path [String] an account's backup path
21
+ # @param folder [String] a folder name
22
+ # @return [String] the full path to a serialized folder (without file extensions)
19
23
  def self.folder_path_for(path:, folder:)
20
24
  relative = File.join(path, folder)
21
25
  File.expand_path(relative)
@@ -26,9 +30,13 @@ module Imap::Backup
26
30
  def_delegator :mbox, :pathname, :mbox_pathname
27
31
  def_delegators :imap, :get, :messages, :uid_validity, :uids, :update_uid
28
32
 
33
+ # @return [String] a folder name
29
34
  attr_reader :folder
35
+ # @return [String] an account's backup path
30
36
  attr_reader :path
31
37
 
38
+ # @param path [String] an account's backup path
39
+ # @param folder [String] a folder name
32
40
  def initialize(path, folder)
33
41
  @path = path
34
42
  @folder = folder
@@ -38,14 +46,17 @@ module Imap::Backup
38
46
  # Calls the supplied block.
39
47
  # This method is present so that this class implements the same
40
48
  # interface as {DelayedMetadataSerializer}
49
+ # @param block [block] the block that is wrapped by the transaction
41
50
  #
42
51
  # @return [void]
43
52
  def transaction(&block)
44
53
  block.call
45
54
  end
46
55
 
47
- # Returns true if there are existing, valid files
48
- # false otherwise (in which case any existing files are deleted)
56
+ # Checks that the metadata files are valid, migrates the metadata file
57
+ # from older versions, if necessary,
58
+ # or deletes any existing files if the pair are not valid.
59
+ # @return [Boolean] indicates whether there are existing, valid files
49
60
  def validate!
50
61
  return true if @validated
51
62
 
@@ -61,16 +72,33 @@ module Imap::Backup
61
72
  false
62
73
  end
63
74
 
75
+ # Checks that the folder's data is stored correctly
76
+ # @return [void]
64
77
  def check_integrity!
65
78
  IntegrityChecker.new(imap: imap, mbox: mbox).run
66
79
  end
67
80
 
81
+ # Deletes the serialized data
82
+ # @return [void]
68
83
  def delete
69
84
  imap.delete
70
85
  mbox.delete
71
86
  reload
72
87
  end
73
88
 
89
+ # Sets the folder's UID validity.
90
+ # If the existing value is nil, it sets the new value
91
+ # and ensures that both the metadata file and the mailbox
92
+ # are saved.
93
+ # If the supplied value is the same as the existing value,
94
+ # it does nothing.
95
+ # If the supplied valued is *different* to the existing value,
96
+ # it renames the existing folder to a new name, and creates a
97
+ # new folder with the supplied value.
98
+ #
99
+ # @param value [Integer] The new UID validity value
100
+ #
101
+ # @return [String, nil] The name of the new folder
74
102
  def apply_uid_validity(value)
75
103
  validate!
76
104
 
@@ -86,12 +114,22 @@ module Imap::Backup
86
114
  end
87
115
  end
88
116
 
117
+ # Overwrites the UID validity of the folder
118
+ # and ensures that both the metadata file and the mailbox
119
+ # are saved.
120
+ # @param value [Integer] the new UID validity
121
+ # @return [void]
89
122
  def force_uid_validity(value)
90
123
  validate!
91
124
 
92
125
  internal_force_uid_validity(value)
93
126
  end
94
127
 
128
+ # Appends a message to the serialized data
129
+ # @param uid [Integer] the message's UID
130
+ # @param message [Integer] the message text
131
+ # @param flags [Array[Symbol]] the message's flags
132
+ # @return [void]
95
133
  def append(uid, message, flags)
96
134
  validate!
97
135
 
@@ -99,6 +137,10 @@ module Imap::Backup
99
137
  appender.append(uid: uid, message: message, flags: flags)
100
138
  end
101
139
 
140
+ # Updates a messages flags
141
+ # @param uid [Integer] the message's UID
142
+ # @param flags [Array<Symbol>] the flags to set on the message
143
+ # @return [void]
102
144
  def update(uid, flags: nil)
103
145
  message = imap.get(uid)
104
146
  return if !message
@@ -107,6 +149,10 @@ module Imap::Backup
107
149
  imap.save
108
150
  end
109
151
 
152
+ # Enumerates over a series of messages.
153
+ # When called without a block, returns an Enumerator
154
+ # @param required_uids [Array<Integer>] the UIDs of the message to enumerate over
155
+ # @return [Enumerator, void]
110
156
  def each_message(required_uids = nil, &block)
111
157
  return enum_for(:each_message, required_uids) if !block
112
158
 
@@ -118,6 +164,10 @@ module Imap::Backup
118
164
  enumerator.run(uids: required_uids, &block)
119
165
  end
120
166
 
167
+ # Calls the supplied block on each message in the folder
168
+ # and discards those for which the block returns a false result
169
+ # @param block [block] the block to call
170
+ # @return [void]
121
171
  def filter(&block)
122
172
  temp_name = Serializer::UnusedNameFinder.new(serializer: self).run
123
173
  temp_folder_path = self.class.folder_path_for(path: path, folder: temp_name)
@@ -137,14 +187,18 @@ module Imap::Backup
137
187
  reload
138
188
  end
139
189
 
190
+ # @return [String] the path to the serialized folder (without file extensions)
140
191
  def folder_path
141
192
  self.class.folder_path_for(path: path, folder: sanitized)
142
193
  end
143
194
 
195
+ # @return [String] The folder's name adapted for using as a file name
144
196
  def sanitized
145
197
  @sanitized ||= Naming.to_local_path(folder)
146
198
  end
147
199
 
200
+ # Forces a reload of the serialized files
201
+ # @return [void]
148
202
  def reload
149
203
  @imap = nil
150
204
  @mbox = nil
@@ -8,12 +8,18 @@ module Imap::Backup
8
8
  class Setup; end
9
9
  class Setup::Account; end
10
10
 
11
+ # Displays the header to the account modification menu
11
12
  class Setup::Account::Header
13
+ # @param menu [Highline::Menu] the menu
14
+ # @param account [Account] an Account
12
15
  def initialize(menu:, account:)
13
16
  @menu = menu
14
17
  @account = account
15
18
  end
16
19
 
20
+ # Displays the header
21
+ #
22
+ # @return [void]
17
23
  def run
18
24
  rows = [
19
25
  email,
@@ -10,13 +10,19 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class Setup; end
12
12
 
13
+ # Handles interactive account setup
13
14
  class Setup::Account
15
+ # @param config [Configuration] the application configuration
16
+ # @param account [Account] an Account
17
+ # @param highline [Higline] the configured Highline instance
14
18
  def initialize(config, account, highline)
15
19
  @account = account
16
20
  @config = config
17
21
  @highline = highline
18
22
  end
19
23
 
24
+ # Shows the menu
25
+ # @return [void]
20
26
  def run
21
27
  if !account.local_path
22
28
  account.local_path = File.join(config.path, account.username.tr("@", "_"))
@@ -3,11 +3,17 @@ module Imap; end
3
3
  module Imap::Backup
4
4
  class Setup; end
5
5
 
6
+ # Implements interactively requesting information from the user
6
7
  class Setup::Asker
8
+ # @param highline [Higline] the configured Highline instance
7
9
  def initialize(highline)
8
10
  @highline = highline
9
11
  end
10
12
 
13
+ # Asks for a email address
14
+ #
15
+ # @param default [String] the existing email address
16
+ # @return [String] the email address
11
17
  def email(default = "")
12
18
  highline.ask("email address: ") do |q|
13
19
  q.default = default
@@ -16,6 +22,9 @@ module Imap::Backup
16
22
  end
17
23
  end
18
24
 
25
+ # Asks for a password
26
+ #
27
+ # @return [String] the password
19
28
  def password
20
29
  password = highline.ask("password: ") { |q| q.echo = false }
21
30
  confirmation = highline.ask("repeat password: ") { |q| q.echo = false }
@@ -29,10 +38,17 @@ module Imap::Backup
29
38
  password
30
39
  end
31
40
 
41
+ # Asks for a email address using the configured menu handler
42
+ #
43
+ # @param default [String] the existing email address
44
+ # @return [String] the email address
32
45
  def self.email(default = "")
33
46
  new(Setup.highline).email(default)
34
47
  end
35
48
 
49
+ # Asks for a password using the configured menu handler
50
+ #
51
+ # @return [String] the password
36
52
  def self.password
37
53
  new(Setup.highline).password
38
54
  end
@@ -3,12 +3,18 @@ module Imap; end
3
3
  module Imap::Backup
4
4
  class Setup; end
5
5
 
6
+ # Requests an updated backup path from the user
6
7
  class Setup::BackupPath
8
+ # @param account [Account] an Account
9
+ # @param config [Configuration] the application configuration
7
10
  def initialize(account:, config:)
8
11
  @account = account
9
12
  @config = config
10
13
  end
11
14
 
15
+ # Asks the user for a backup path
16
+ #
17
+ # @return [void]
12
18
  def run
13
19
  account.local_path = highline.ask("backup directory: ") do |q|
14
20
  q.default = account.local_path
@@ -5,11 +5,16 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  class Setup; end
7
7
 
8
+ # Attempts to login to an account and reports the result
8
9
  class Setup::ConnectionTester
10
+ # @param account [Account] an Account
9
11
  def initialize(account)
10
12
  @account = account
11
13
  end
12
14
 
15
+ # Carries out the attempted login and indicates
16
+ # whether it was successful
17
+ # @return [void]
13
18
  def test
14
19
  account.client.login
15
20
  "Connection successful"
@@ -6,12 +6,18 @@ module Imap; end
6
6
  module Imap::Backup
7
7
  class Setup; end
8
8
 
9
+ # Asks the user for a new email address
9
10
  class Setup::EmailChanger
11
+ # @param account [Account] an Account
12
+ # @param config [Configuration] the application configuration
10
13
  def initialize(account:, config:)
11
14
  @account = account
12
15
  @config = config
13
16
  end
14
17
 
18
+ # Asks the user for an email address,
19
+ # ensuring that the supplied address is not an existing account
20
+ # @return [void]
15
21
  def run
16
22
  username = Setup::Asker.email(account.username)
17
23
  other_accounts = config.accounts.reject { |a| a == account }
@@ -5,11 +5,15 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  class Setup; end
7
7
 
8
+ # Allows the user to select and deselect folders to be backed up
8
9
  class Setup::FolderChooser
10
+ # @param account [Account] an Account
9
11
  def initialize(account)
10
12
  @account = account
11
13
  end
12
14
 
15
+ # Lists account folders and allows the user to toggle whther they are selected
16
+ # @return [void]
13
17
  def run
14
18
  if client.nil?
15
19
  highline.ask "Press a key "
@@ -5,11 +5,15 @@ module Imap::Backup; end
5
5
  class Imap::Backup::Setup; end
6
6
 
7
7
  class Imap::Backup::Setup::GlobalOptions
8
+ # Allows changing the globally configured download strategy
8
9
  class DownloadStrategyChooser
10
+ # @param config [Configuration] the application configuration
9
11
  def initialize(config:)
10
12
  @config = config
11
13
  end
12
14
 
15
+ # Shows the menu
16
+ # @return [void]
13
17
  def run
14
18
  catch :done do
15
19
  loop do
@@ -6,11 +6,15 @@ module Imap; end
6
6
  module Imap::Backup
7
7
  class Setup; end
8
8
 
9
+ # Shows the menu of global options
9
10
  class Setup::GlobalOptions
11
+ # @param config [Configuration] the application configuration
10
12
  def initialize(config:)
11
13
  @config = config
12
14
  end
13
15
 
16
+ # Shows the menu
17
+ # @return [void]
14
18
  def run
15
19
  catch :done do
16
20
  loop do
@@ -5,11 +5,14 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  class Setup; end
7
7
 
8
+ # Helpers for the setup system
8
9
  class Setup::Helpers
10
+ # @return [String] the prefix for setup menus
9
11
  def title_prefix
10
12
  "imap-backup -"
11
13
  end
12
14
 
15
+ # @return [String] the current application version
13
16
  def version
14
17
  VERSION
15
18
  end
@@ -10,16 +10,21 @@ require "imap/backup/setup/helpers"
10
10
  module Imap; end
11
11
 
12
12
  module Imap::Backup
13
+ # Interactively updates the application's configuration file
13
14
  class Setup
14
15
  class << self
16
+ # @return [Highline]
15
17
  attr_accessor :highline
16
18
  end
17
19
  self.highline = HighLine.new
18
20
 
21
+ # @param config [Configuration] the application configuration
19
22
  def initialize(config:)
20
23
  @config = config
21
24
  end
22
25
 
26
+ # Shows the menu
27
+ # @return [void]
23
28
  def run
24
29
  catch :done do
25
30
  loop do
@@ -5,17 +5,24 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  module Text; end
7
7
 
8
+ # Wraps standard output and hides passwords from debug output
9
+ # Any text matching Net::IMAP debug output of passwords is sanitized
8
10
  class Text::Sanitizer
9
11
  extend Forwardable
10
12
 
11
13
  delegate puts: :output
12
14
  delegate write: :output
13
15
 
16
+ # @param output [IO] the stream to write output to
14
17
  def initialize(output)
15
18
  @output = output
16
19
  @current = ""
17
20
  end
18
21
 
22
+ # Outputs everything up to the last newline character,
23
+ # storing whatever follows the newline.
24
+ # @param args [Array<String>] lines of text
25
+ # @return [void]
19
26
  def print(*args)
20
27
  @current << args.join
21
28
  loop do
@@ -28,6 +35,8 @@ module Imap::Backup
28
35
  end
29
36
  end
30
37
 
38
+ # Outputs any text still not printed
39
+ # @return [void]
31
40
  def flush
32
41
  return if @current == ""
33
42