imap-backup 14.4.4 → 14.4.5

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 (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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc28eee3a2ef71157ebe6e50490488ce92b101bb3c4e02a46964b398ddc85d83
4
- data.tar.gz: e6ee9d519463a25bf391fb71bf426d59aeaf27072afdf6306bbe631703a82dfb
3
+ metadata.gz: e492fd50201bbf2424231905b4cdb6fe3d44d99fa446c624b851c9ef50eb686f
4
+ data.tar.gz: e2ed159ec5e92e7d97a685093456491afe94d34e70702d4e7a0449cf150009dd
5
5
  SHA512:
6
- metadata.gz: 0004c4453debba185805fdce233f450570b6bf5a11ae6976641abf91b3adbbc33f62c8da195bcc3eccf99119203cf270bd1506c6620564a81f0c64197814c738
7
- data.tar.gz: 378acbd1e668f87b76ebd2db0649344e2904f8992ee4c60aff2f5cf539a145b411fc39bdca962fc4c60e81ed444919b84bf3c305a0199b09fbbd1eb1c87d5d72
6
+ metadata.gz: d0f4acc27fa79b789c83298af7788c01e9b8c837aa5086d1675e98b7ef80abd7fe1b3decb4b36c3f586126f7d9dc54499358bc05f7e65e0de3cbc29207233188
7
+ data.tar.gz: e036ad78bff71f98012907444f5eb36c56e01f3a3a8d2f37fbb0b06f5c1850eaddd26a4be86a8581a8f25e322731eac06a25a18853ac4433a2793cbd603b8727
data/README.md CHANGED
@@ -1,201 +1,131 @@
1
+ # imap-backup API Documentation
2
+
1
3
  ![Version](https://img.shields.io/gem/v/imap-backup?label=Version&logo=rubygems)
2
4
  [![Build Status](https://github.com/joeyates/imap-backup/actions/workflows/main.yml/badge.svg)][CI Status]
3
5
  ![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/joeyates/b54fe758bfb405c04bef72dad293d707/raw/coverage.json)
4
6
  ![License](https://img.shields.io/github/license/joeyates/imap-backup?color=brightgreen&label=License)
5
7
  [![Stars](https://img.shields.io/github/stars/joeyates/imap-backup?style=social)][GitHub Stars]
8
+ ![Activity](https://img.shields.io/github/last-commit/joeyates/imap-backup/main)
6
9
 
7
- # imap-backup
8
-
9
- Backup, restore and migrate email accounts.
10
-
11
- # Quick Start
12
-
13
- ```sh
14
- brew install imap-backup # for macOS
15
- gem install imap-backup --no-document # for Linux
16
- imap-backup setup
17
- imap-backup
18
- ```
19
-
20
- # Modes
21
-
22
- There are two types of backups:
23
-
24
- * Keep all (the default) - progressively saves a local copy of all emails,
25
- * Mirror - adds and deletes emails from the local copy to keep it up to date with the account.
10
+ [CI Status]: https://github.com/joeyates/imap-backup/actions/workflows/main.yml
11
+ [GitHub Stars]: https://github.com/joeyates/imap-backup/stargazers "GitHub Stars"
26
12
 
27
- # What You Can Do with a Backup
13
+ This is the developer documentation for imap-backup's **code**.
28
14
 
29
- * Migrate - use the local copy to populate emails on another account. This is a once-only action that deletes any existing emails on the destination account.
30
- * Mirror - make a destination account match the local copy. This action can be repeated.
31
- * Restore - push the local copy back to the original account.
15
+ Usage documentation is on [GitHub](https://github.com/joeyates/imap-backup).
32
16
 
33
- See below for a [full list of commands](#commands).
17
+ You can get an overview of the program's structure from the
18
+ {file:ARCHITECTURE.md ARCHITECTURE} file.
34
19
 
35
- # Installation
20
+ The {file:CHANGELOG.md CHANGELOG} has a history of the changes to the program.
36
21
 
37
- ## Docker or Podman
22
+ # Design Goals
38
23
 
39
- If you have Docker or Podman installed, the easist way to use imap-backup
40
- is via the container image.
24
+ * Secure - use a local configuration file protected by permissions
25
+ * Restartable - calculate start point based on already downloaded messages
26
+ * Standalone - do not rely on an email client or MTA
41
27
 
42
- You'll need to choose a path on your computer where your backups will be saved,
43
- we'll use `./my-data` here.
28
+ # Repository
44
29
 
45
- If you have just one account, you can do as follows
30
+ After cloning the repo, run the following command to get
31
+ better `git blame` output:
46
32
 
47
33
  ```sh
48
- docker run -v ./my-data:/data -ti ghcr.io/joeyates/imap-backup:latest \
49
- imap-backup single backup \
50
- --email me@example.com --password mysecret --server imap.example.com \
51
- --path /data/me_example.com
34
+ git config --local blame.ignoreRevsFile .git-blame-ignore-revs
52
35
  ```
53
36
 
54
- Podman will work exactly the same.
37
+ # Testing
55
38
 
56
- If you have multiple accounts, you can create a configuration file.
39
+ ## Feature Specs
57
40
 
58
- You'll need to choose a path on your computer where your configuration will be saved,
59
- we'll use `./my-config` here.
41
+ Specs under `specs/features` are integration specs.
42
+ Some of these specs run against two local IMAP servers
43
+ controlled by Podman (or Docker) Compose.
60
44
 
61
- First, run the menu-driven setup program to configure your accounts
45
+ Start them before running the test suite
62
46
 
63
47
  ```sh
64
- docker run -ti -v ./my-config:/config -v ./my-data:/data -ti ghcr.io/joeyates/imap-backup:latest \
65
- imap-backup setup -c /config/imap-backup.json
48
+ $ podman-compose -f dev/compose.yml up -d
66
49
  ```
67
50
 
68
- Then, run the backup
51
+ or, with Docker
69
52
 
70
53
  ```sh
71
- docker run -v ./my-config:/config -v ./my-data:/data -ti ghcr.io/joeyates/imap-backup:latest \
72
- imap-backup backup -c /config/imap-backup.json
54
+ $ docker-compose -f dev/compose.yml up -d
73
55
  ```
74
56
 
75
-
76
- ## Homebrew (macOS)
77
-
78
- ![Homebrew installs](https://img.shields.io/homebrew/installs/dm/imap-backup?label=Homebrew%20installs)
79
-
80
- If you have [Homebrew](https://brew.sh/), do this:
57
+ Then, run all specs
81
58
 
82
59
  ```sh
83
- brew install imap-backup
60
+ $ rspec
84
61
  ```
85
62
 
86
- ## As a Ruby Gem
63
+ To exclude container-based tests
87
64
 
88
65
  ```sh
89
- gem install imap-backup --no-document
66
+ $ rspec --tag ~docker
90
67
  ```
91
68
 
92
- If that doesn't work, see the [detailed installation instructions](docs/installation/rubygem.md).
93
-
94
- ## From Source Code
95
-
96
- If you want to use imap-backup directly from the source code, see [here](docs/installation/source.md).
97
-
98
- # Setup
99
-
100
- Normally you will want to backup a number of email accounts.
101
- Doing so requires the creation of a config file.
102
-
103
- You do this via a menu-driven command line program:
104
-
105
- Run:
69
+ To run **just** the feature specs
106
70
 
107
71
  ```sh
108
- imap-backup setup
72
+ rspec spec/features/**/*_spec.rb
109
73
  ```
110
74
 
111
- As an alternative, if you only want to backup a single account,
112
- you can pass all the necessary parameters directly to the `single backup` command
113
- (see the [`single backup`](docs/commands/single-backup.md) docs).
114
-
115
- ## GMail
116
-
117
- To use imap-backup with GMail, Office 365 and other services that require
118
- OAuth2 authentication, you can use [email-oauth2-proxy](https://github.com/simonrob/email-oauth2-proxy).
119
- See [this blog post about using imap-backup with email-oauth2-proxy](https://joeyates.info/posts/back-up-gmail-accounts-with-imap-backup-using-email-oauth2-proxy/).
75
+ ## Full Test Run
120
76
 
121
- # Backup
122
-
123
- Manually, from the command line:
77
+ The full test run includes RSpec specs **and** Rubocop checks
124
78
 
125
79
  ```sh
126
- imap-backup
80
+ rake
127
81
  ```
128
82
 
129
- Alternatively, add it to your crontab.
83
+ # Test Debugging
130
84
 
131
- Backups can also be inspected, for example via [`local show`](docs/commands/local-show.md)
132
- and exported via [`utils export-to-thunderbird`](docs/commands/utils-export-to-thunderbird.md).
85
+ The feature specs are run 'out of process' via the Aruba gem.
86
+ In order to see debugging output from the process,
87
+ use `last_command_started.output`.
133
88
 
134
- # Commands
89
+ # Older Rubies
135
90
 
136
- * [`backup`](docs/commands/backup.md)
137
- * [`local accounts`](docs/commands/local-accounts.md)
138
- * [`local check`](docs/commands/local-check.md)
139
- * [`local folders`](docs/commands/local-folders.md)
140
- * [`local list`](docs/commands/local-list.md)
141
- * [`local show`](docs/commands/local-show.md)
142
- * [`migrate`](docs/commands/migrate.md)
143
- * [`mirror`](docs/commands/mirror.md)
144
- * [`remote folders`](docs/commands/remote-folders.md)
145
- * [`restore`](docs/commands/restore.md)
146
- * [`setup`](docs/commands/setup.md)
147
- * [`single backup`](docs/commands/single-backup.md)
148
- * [`utils export-to-thunderbird`](docs/commands/utils-export-to-thunderbird.md)
149
- * [`utils ignore-history`](docs/commands/utils-ignore-history.md)
91
+ A Containerfile is available to allow testing with all available Ruby versions,
92
+ see the README in the `dev` directory.
150
93
 
151
- For a full list of available commands, run
94
+ # Performance Specs
152
95
 
153
96
  ```sh
154
- imap-backup help
97
+ PERFORMANCE=1 rspec --order=defined
155
98
  ```
156
99
 
157
- For more information about a command, run
158
-
159
- ```sh
160
- imap-backup help COMMAND
161
- ```
100
+ Beware: the performance spec (just backup for now) takes a very
101
+ long time to run, approximately 24 hours!
162
102
 
163
- # Performance
103
+ # Access Docker imap server
164
104
 
165
- There are a couple of performance tweaks that you can use
166
- to improve backup speed.
105
+ ```ruby
106
+ require "net/imap"
107
+ require_relative "spec/features/support/30_email_server_helpers"
167
108
 
168
- These are activated via two settings:
109
+ include EmailServerHelpers
169
110
 
170
- * Global setting "Delay download writes",
171
- * Account setting "Multi-fetch size".
111
+ test_connection = test_server_connection_parameters
172
112
 
173
- See [the performance document](docs/performance.md) for more information.
113
+ test_imap = Net::IMAP.new(test_connection[:server], test_connection[:connection_options])
114
+ test_imap.login(test_connection[:username], test_connection[:password])
174
115
 
175
- # Troubleshooting
116
+ message = "From: #{test_connection[:username]}\nSubject: Some Subject\n\nHello!\n"
117
+ response = test_imap.append("INBOX", message, nil, nil)
176
118
 
177
- If you have problems:
119
+ test_imap.examine("INBOX")
120
+ uids = test_imap.uid_search(["ALL"]).sort
178
121
 
179
- 1. ensure that you have the latest release,
180
- 2. run `imap-backup` with the `-v` or `--verbose` parameter.
181
-
182
- # Development
183
-
184
- ![Activity](https://img.shields.io/github/last-commit/joeyates/imap-backup/main)
185
-
186
- See the [Development documentation](./docs/development.md) for notes
187
- on development and testing.
188
-
189
- See [the CHANGELOG](./CHANGELOG.md) for a list of changes that have been
190
- made in each release.
122
+ fetch_data_items = test_imap.uid_fetch(uids, ["BODY[]"])
123
+ ```
191
124
 
192
- * [Source Code]
193
- * [Code Documentation]
194
- * [Rubygem]
195
- * [CI Status]
125
+ # Contributing
196
126
 
197
- [Source Code]: https://github.com/joeyates/imap-backup "Source code at GitHub"
198
- [GitHub Stars]: https://github.com/joeyates/imap-backup/stargazers "GitHub Stars"
199
- [Code Documentation]: https://rubydoc.info/gems/imap-backup/frames "Code Documentation at Rubydoc.info"
200
- [Rubygem]: https://rubygems.org/gems/imap-backup "Ruby gem at rubygems.org"
201
- [CI Status]: https://github.com/joeyates/imap-backup/actions/workflows/main.yml
127
+ 1. Fork it
128
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
129
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
130
+ 4. Push to the branch (`git push origin my-new-feature`)
131
+ 5. Create new Pull Request
@@ -0,0 +1,19 @@
1
+ # Documentation
2
+
3
+ This project uses [yard](https://yardoc.org/) to generate its documentation.
4
+
5
+ # Development
6
+
7
+ Run an autoreloading document viewer
8
+
9
+ ```
10
+ yard server --reload
11
+ ```
12
+
13
+ # Coverage
14
+
15
+ See what's not documented
16
+
17
+ ```
18
+ yard stats --list-undoc
19
+ ```
@@ -15,6 +15,8 @@ module Imap::Backup
15
15
  @refresh = refresh
16
16
  end
17
17
 
18
+ # Runs the backup
19
+ # @return [void]
18
20
  def run
19
21
  Logger.logger.info "Running backup of account: #{account.username}"
20
22
  # start the connection so we get logging messages in the right order
@@ -5,7 +5,7 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  class Account; end
7
7
 
8
- # Iterates over the account folders that are to be backed up
8
+ # Enumerates over the account folders that are to be backed up
9
9
  class Account::BackupFolders
10
10
  include Enumerable
11
11
 
@@ -14,6 +14,9 @@ module Imap::Backup
14
14
  @account = account
15
15
  end
16
16
 
17
+ # Runs the enumeration
18
+ # @yieldparam folder [Account::Folder] the online folder
19
+ # @return [void]
17
20
  def each(&block)
18
21
  return enum_for(:each) if !block
19
22
 
@@ -39,6 +42,9 @@ module Imap::Backup
39
42
  names.each { |name| block.call(Account::Folder.new(client, name)) }
40
43
  end
41
44
 
45
+ # Runs a map operation over the folders
46
+ # @yieldparam folder [Account::Folder] the online folder
47
+ # @return The results of the map operation
42
48
  def map(&block)
43
49
  each.map do |folder|
44
50
  block.call(folder)
@@ -18,6 +18,7 @@ module Imap::Backup
18
18
  @server = nil
19
19
  end
20
20
 
21
+ # @return [Client::AutomaticLoginWrapper] a client for the account
21
22
  def run
22
23
  options = provider_options
23
24
  Logger.logger.debug(
@@ -12,12 +12,15 @@ module Imap::Backup
12
12
 
13
13
  # Handles access to a folder on an IMAP server
14
14
  class Account::Folder
15
+ # An error that is thrown if a requestd folder does not exist
15
16
  class FolderNotFound < StandardError; end
16
17
 
17
18
  extend Forwardable
18
19
  include RetryOnError
19
20
 
21
+ # @return [Client::Default]
20
22
  attr_reader :client
23
+ # @return [String] the name of the folder
21
24
  attr_reader :name
22
25
 
23
26
  def initialize(client, name)
@@ -26,6 +29,7 @@ module Imap::Backup
26
29
  @uid_validity = nil
27
30
  end
28
31
 
32
+ # @raise any error that occurs more than 10 times
29
33
  def exist?
30
34
  previous_level = Imap::Backup::Logger.logger.level
31
35
  previous_debug = Net::IMAP.debug
@@ -42,6 +46,8 @@ module Imap::Backup
42
46
  Net::IMAP.debug = previous_debug
43
47
  end
44
48
 
49
+ # Creates the folder on the server
50
+ # @return [void]
45
51
  def create
46
52
  return if exist?
47
53
 
@@ -50,6 +56,8 @@ module Imap::Backup
50
56
  end
51
57
  end
52
58
 
59
+ # @raise any error that occurs more than 10 times
60
+ # @return [Integer] the folder's UID validity
53
61
  def uid_validity
54
62
  @uid_validity ||=
55
63
  begin
@@ -58,6 +66,8 @@ module Imap::Backup
58
66
  end
59
67
  end
60
68
 
69
+ # @raise any error that occurs more than 10 times
70
+ # @return [Array<Integer>] the folders message UIDs
61
71
  def uids
62
72
  examine
63
73
  client.uid_search(["ALL"]).sort
@@ -75,6 +85,8 @@ module Imap::Backup
75
85
  []
76
86
  end
77
87
 
88
+ # @raise any error that occurs more than 10 times
89
+ # @return [Array<Hash>, nil] the requested messages
78
90
  def fetch_multi(uids, attr = [BODY_ATTRIBUTE, "FLAGS"])
79
91
  examine
80
92
  fetch_data_items =
@@ -96,6 +108,8 @@ module Imap::Backup
96
108
  nil
97
109
  end
98
110
 
111
+ # Uploads a message
112
+ # @return [void]
99
113
  def append(message)
100
114
  body = message.imap_body
101
115
  date = message.date&.to_time
@@ -106,17 +120,23 @@ module Imap::Backup
106
120
  end
107
121
  end
108
122
 
123
+ # Deletes multiple messages
124
+ # @return [void]
109
125
  def delete_multi(uids)
110
126
  add_flags(uids, [:Deleted])
111
127
  client.expunge
112
128
  end
113
129
 
130
+ # Sets one or more flags on a group of messages
131
+ # @return [void]
114
132
  def set_flags(uids, flags)
115
133
  client.select(utf7_encoded_name)
116
134
  flags.reject! { |f| f == :Recent }
117
135
  client.uid_store(uids, "FLAGS", flags)
118
136
  end
119
137
 
138
+ # Adds one or more flags to a group of messages
139
+ # @return [void]
120
140
  def add_flags(uids, flags)
121
141
  # Use read-write access, via `select`
122
142
  client.select(utf7_encoded_name)
@@ -124,11 +144,15 @@ module Imap::Backup
124
144
  client.uid_store(uids, "+FLAGS", flags)
125
145
  end
126
146
 
147
+ # Removes one or more flags from a group of messages
148
+ # @return [void]
127
149
  def remove_flags(uids, flags)
128
150
  client.select(utf7_encoded_name)
129
151
  client.uid_store(uids, "-FLAGS", flags)
130
152
  end
131
153
 
154
+ # Deletes all messages from the folder
155
+ # @return [void]
132
156
  def clear
133
157
  existing = uids
134
158
  return if existing.empty?
@@ -137,6 +161,8 @@ module Imap::Backup
137
161
  client.expunge
138
162
  end
139
163
 
164
+ # @raise any error that occurs more than 10 times
165
+ # @return [Array<Integer>] the UIDs of messages with the 'UNSEEN' flag
140
166
  def unseen(uids)
141
167
  messages = uids.map(&:to_s).join(",")
142
168
  examine
@@ -10,7 +10,7 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class Account; end
12
12
 
13
- # Runs a backup for a single account folder
13
+ # Implements backup for a single folder
14
14
  class Account::FolderBackup
15
15
  def initialize(account:, folder:, refresh: false)
16
16
  @account = account
@@ -18,6 +18,9 @@ module Imap::Backup
18
18
  @refresh = refresh
19
19
  end
20
20
 
21
+ # Runs the backup
22
+ # @raise [RuntimeError] if the configured download strategy is incorrect
23
+ # @return [void]
21
24
  def run
22
25
  folder_ok = folder_ok?
23
26
  return if !folder_ok
@@ -12,6 +12,9 @@ module Imap::Backup
12
12
  @account = account
13
13
  end
14
14
 
15
+ # Creates the account's base directory and sets its permissions
16
+ # @raise [RuntimeError] is the account's backup path is not set
17
+ # @return [void]
15
18
  def run
16
19
  raise "The backup path for #{account.username} is not set" if !account.local_path
17
20
 
@@ -14,6 +14,8 @@ module Imap::Backup
14
14
  @account = account
15
15
  end
16
16
 
17
+ # Runs the deletion operation
18
+ # @return [void]
17
19
  def run
18
20
  backup_folders = Account::BackupFolders.new(
19
21
  client: account.client, account: account
@@ -12,6 +12,8 @@ module Imap::Backup
12
12
  @account = account
13
13
  end
14
14
 
15
+ # Runs the restore operation
16
+ # @return [void]
15
17
  def run
16
18
  serialized_folders = Account::SerializedFolders.new(account: account)
17
19
  serialized_folders.each do |serializer, folder|
@@ -9,7 +9,7 @@ module Imap; end
9
9
  module Imap::Backup
10
10
  class Account; end
11
11
 
12
- # Enumerates over the folders that are backed up to an account
12
+ # Enumerates over an account's backed-up folders
13
13
  class Account::SerializedFolders
14
14
  include Enumerable
15
15
 
@@ -17,6 +17,10 @@ module Imap::Backup
17
17
  @account = account
18
18
  end
19
19
 
20
+ # Runs the enumeration
21
+ # @yieldparam serializer [Serializer] the folder's serializer
22
+ # @yieldparam folder [Account::Folder] the online folder
23
+ # @return [void]
20
24
  def each(&block)
21
25
  return enum_for(:each) if !block
22
26
 
@@ -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,6 +37,7 @@ 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]
@@ -61,8 +61,6 @@ module Imap::Backup
61
61
  # mark messages as '\Seen' when accessed).
62
62
  # @return [Boolean]
63
63
  attr_reader :reset_seen_flags_after_fetch
64
- # Tracks changes to the Account's attributes
65
- attr_reader :changes
66
64
 
67
65
  def initialize(options)
68
66
  @username = options[:username]
@@ -123,6 +121,7 @@ module Imap::Backup
123
121
  end
124
122
 
125
123
  # Resets the store of changes, indicating that the current state is the saved state
124
+ # @return [void]
126
125
  def clear_changes
127
126
  @changes = {}
128
127
  end
@@ -134,16 +133,12 @@ module Imap::Backup
134
133
  @marked_for_deletion = true
135
134
  end
136
135
 
137
- # Indicates whether the account has been flagged for deletion during setup
138
- #
139
- # @return [Boolean]
136
+ # @return [Boolean] whether the account has been flagged for deletion during setup
140
137
  def marked_for_deletion?
141
138
  @marked_for_deletion
142
139
  end
143
140
 
144
- # Returns all Account data for serialization
145
- #
146
- # @return [Hash]
141
+ # @return [Hash] all Account data for serialization
147
142
  def to_h
148
143
  h = {username: @username, password: @password}
149
144
  h[:local_path] = @local_path if @local_path
@@ -180,24 +175,30 @@ module Imap::Backup
180
175
  update(:local_path, value)
181
176
  end
182
177
 
178
+ # @raise [RuntimeError] if the supplied value is not an Array
179
+ # @return [void]
183
180
  def folders=(value)
184
181
  raise "folders must be an Array" if !value.is_a?(Array)
185
182
 
186
183
  update(:folders, value)
187
184
  end
188
185
 
186
+ # @return [void]
189
187
  def folder_blacklist=(value)
190
188
  update(:folder_blacklist, value)
191
189
  end
192
190
 
191
+ # @return [void]
193
192
  def mirror_mode=(value)
194
193
  update(:mirror_mode, value)
195
194
  end
196
195
 
196
+ # @return [void]
197
197
  def server=(value)
198
198
  update(:server, value)
199
199
  end
200
200
 
201
+ # @return [void]
201
202
  def connection_options=(value)
202
203
  parsed =
203
204
  if value == ""
@@ -232,12 +233,15 @@ module Imap::Backup
232
233
  update(:multi_fetch_size, parsed)
233
234
  end
234
235
 
236
+ # @return [void]
235
237
  def reset_seen_flags_after_fetch=(value)
236
238
  update(:reset_seen_flags_after_fetch, value)
237
239
  end
238
240
 
239
241
  private
240
242
 
243
+ attr_reader :changes
244
+
241
245
  def update(field, value)
242
246
  key = :"@#{field}"
243
247
  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