imap-backup 4.0.0 → 4.0.4
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.
- checksums.yaml +4 -4
- data/README.md +17 -49
- data/docs/development.md +53 -0
- data/docs/restore.md +17 -0
- data/imap-backup.gemspec +4 -7
- data/lib/email/mboxrd/message.rb +6 -2
- data/lib/email/provider/apple_mail.rb +7 -0
- data/lib/email/provider/default.rb +12 -0
- data/lib/email/provider/fastmail.rb +7 -0
- data/lib/email/provider/gmail.rb +7 -0
- data/lib/email/provider.rb +16 -26
- data/lib/imap/backup/account/connection.rb +19 -29
- data/lib/imap/backup/account/folder.rb +9 -10
- data/lib/imap/backup/cli/helpers.rb +14 -1
- data/lib/imap/backup/cli/local.rb +22 -28
- data/lib/imap/backup/cli/setup.rb +1 -1
- data/lib/imap/backup/cli/utils.rb +98 -0
- data/lib/imap/backup/cli.rb +5 -1
- data/lib/imap/backup/client/apple_mail.rb +11 -0
- data/lib/imap/backup/client/default.rb +51 -0
- data/lib/imap/backup/configuration/account.rb +3 -1
- data/lib/imap/backup/configuration/connection_tester.rb +1 -1
- data/lib/imap/backup/configuration/store.rb +10 -5
- data/lib/imap/backup/downloader.rb +3 -4
- data/lib/imap/backup/serializer/mbox.rb +5 -0
- data/lib/imap/backup/serializer/mbox_store.rb +8 -8
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +58 -0
- data/lib/imap/backup/version.rb +1 -1
- data/lib/imap/backup.rb +1 -0
- data/lib/thunderbird/install.rb +16 -0
- data/lib/thunderbird/local_folder.rb +65 -0
- data/lib/thunderbird/profile.rb +30 -0
- data/lib/thunderbird/profiles.rb +71 -0
- data/lib/thunderbird/subdirectory.rb +96 -0
- data/lib/thunderbird/subdirectory_placeholder.rb +21 -0
- data/lib/thunderbird.rb +14 -0
- data/spec/features/restore_spec.rb +1 -1
- data/spec/features/support/email_server.rb +2 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/email/provider/apple_mail_spec.rb +7 -0
- data/spec/unit/email/provider/default_spec.rb +17 -0
- data/spec/unit/email/provider/fastmail_spec.rb +7 -0
- data/spec/unit/email/provider/gmail_spec.rb +7 -0
- data/spec/unit/email/provider_spec.rb +12 -25
- data/spec/unit/imap/backup/account/connection_spec.rb +26 -51
- data/spec/unit/imap/backup/account/folder_spec.rb +22 -22
- data/spec/unit/imap/backup/cli/local_spec.rb +70 -0
- data/spec/unit/imap/backup/cli/utils_spec.rb +50 -0
- data/spec/unit/imap/backup/client/default_spec.rb +22 -0
- data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +3 -3
- data/spec/unit/imap/backup/configuration/store_spec.rb +25 -12
- data/spec/unit/imap/backup/downloader_spec.rb +1 -2
- metadata +71 -28
- data/docs/docker-imap.md +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69ed28d85dda7c3d30cd6c8d4a9888e9f477eedd6f8ff08741fcc7d27cf087f8
|
4
|
+
data.tar.gz: 1a99e7143052a1d0b1b2d58381c5f9da0db2b1e0e3882c24e56036cebead043f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: deb80ed5d629c81253574d96a7da0dcc6382eb6d5216c1f317b8083ca0f4dac80a3188cbc0b7f46ffbc01229dad9ab913858649558ca7b3a29bf7b81395bcce3
|
7
|
+
data.tar.gz: 2e6b2b8d2c67c6bc1e3ff5dcbb91c4eec92d0edb87ff33ad6e8a360b6635895c72cc7eb4cc68a7ff24bcfbad5a3533bda0a916e3c4d0c40ee67de70a010d4b2b
|
data/README.md
CHANGED
@@ -16,10 +16,6 @@
|
|
16
16
|
[Rubygem]: http://rubygems.org/gems/imap-backup "Ruby gem at rubygems.org"
|
17
17
|
[Continuous Integration]: https://circleci.com/gh/joeyates/imap-backup "Build status by CirceCI"
|
18
18
|
|
19
|
-
# GMail
|
20
|
-
|
21
|
-
To use imap-backup with GMail, you will need to enable 'App passwords' on your account.
|
22
|
-
|
23
19
|
# Installation
|
24
20
|
|
25
21
|
```shell
|
@@ -51,6 +47,10 @@ Run:
|
|
51
47
|
$ imap-backup setup
|
52
48
|
```
|
53
49
|
|
50
|
+
## GMail
|
51
|
+
|
52
|
+
To use imap-backup with GMail, you will need to enable 'App passwords' on your account.
|
53
|
+
|
54
54
|
## Folders
|
55
55
|
|
56
56
|
By default, all folders are backed-up. You can override this by choosing
|
@@ -134,7 +134,15 @@ in the configuration file.
|
|
134
134
|
|
135
135
|
The directory ~/.imap-backup, the configuration file and all backup
|
136
136
|
directories have their access permissions set to only allow access
|
137
|
-
by your user.
|
137
|
+
by your user. This is not done on Windows - see below.
|
138
|
+
|
139
|
+
## Windows
|
140
|
+
|
141
|
+
Due to the complexity of managing permissions on Windows,
|
142
|
+
directory and file access permissions are not set explicity.
|
143
|
+
|
144
|
+
A pull request that implements permissions management on Windows
|
145
|
+
would be welcome!
|
138
146
|
|
139
147
|
# Run Backup
|
140
148
|
|
@@ -178,6 +186,7 @@ If you have problems:
|
|
178
186
|
"debug": true
|
179
187
|
}
|
180
188
|
```
|
189
|
+
|
181
190
|
# Restore
|
182
191
|
|
183
192
|
All missing messages are pushed to the IMAP server.
|
@@ -206,48 +215,7 @@ $ imap-backup status
|
|
206
215
|
* Restartable - calculate start point based on already downloaded messages
|
207
216
|
* Standalone - do not rely on an email client or MTA
|
208
217
|
|
209
|
-
#
|
210
|
-
|
211
|
-
* https://github.com/OfflineIMAP/offlineimap
|
212
|
-
|
213
|
-
# Testing
|
214
|
-
|
215
|
-
## Integration Tests
|
216
|
-
|
217
|
-
Integration tests (feature specs) are run against a Docker image
|
218
|
-
(antespi/docker-imap-devel:latest).
|
219
|
-
|
220
|
-
In one shell, run the Docker image:
|
221
|
-
|
222
|
-
```sh
|
223
|
-
$ docker run \
|
224
|
-
--env MAIL_ADDRESS=address@example.org \
|
225
|
-
--env MAIL_PASS=pass \
|
226
|
-
--env MAILNAME=example.org \
|
227
|
-
--publish 8993:993 \
|
228
|
-
antespi/docker-imap-devel:latest
|
229
|
-
```
|
230
|
-
|
231
|
-
```sh
|
232
|
-
$ rake
|
233
|
-
```
|
234
|
-
|
235
|
-
To exclude Docker-based tests:
|
236
|
-
|
237
|
-
```sh
|
238
|
-
rake no-docker
|
239
|
-
```
|
240
|
-
|
241
|
-
or
|
242
|
-
|
243
|
-
```sh
|
244
|
-
$ rspec --tag ~docker
|
245
|
-
```
|
246
|
-
|
247
|
-
## Contributing
|
218
|
+
# Documentation
|
248
219
|
|
249
|
-
|
250
|
-
|
251
|
-
3. Commit your changes (`git commit -am 'Added some feature'`)
|
252
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
253
|
-
5. Create new Pull Request
|
220
|
+
* [Development](./docs/development.md)
|
221
|
+
* [Restore](./docs/restore.md)
|
data/docs/development.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Testing
|
2
|
+
|
3
|
+
## Integration Tests
|
4
|
+
|
5
|
+
Integration tests (feature specs) are run against a local IMAP server
|
6
|
+
controlled by Docker Compose, which needs to be started
|
7
|
+
before running the test suite.
|
8
|
+
|
9
|
+
```sh
|
10
|
+
$ docker-compose up -d
|
11
|
+
```
|
12
|
+
|
13
|
+
```sh
|
14
|
+
$ rake
|
15
|
+
```
|
16
|
+
|
17
|
+
To exclude Docker-based tests:
|
18
|
+
|
19
|
+
```sh
|
20
|
+
rake no-docker
|
21
|
+
```
|
22
|
+
|
23
|
+
or
|
24
|
+
|
25
|
+
```sh
|
26
|
+
$ rspec --tag ~docker
|
27
|
+
```
|
28
|
+
|
29
|
+
## Access Docker imap server
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require "net/imap"
|
33
|
+
|
34
|
+
imap = Net::IMAP.new("localhost", {port: 8993, ssl: {verify_mode: 0}})
|
35
|
+
username = "address@example.org"
|
36
|
+
imap.login(username, "pass")
|
37
|
+
|
38
|
+
message = "From: #{username}\nSubject: Some Subject\n\nHello!\n"
|
39
|
+
response = imap.append("INBOX", message, nil, nil)
|
40
|
+
|
41
|
+
imap.examine("INBOX")
|
42
|
+
uids = imap.uid_search(["ALL"]).sort
|
43
|
+
|
44
|
+
fetch_data_items = imap.uid_fetch(uids, ["BODY[]"])
|
45
|
+
```
|
46
|
+
|
47
|
+
# Contributing
|
48
|
+
|
49
|
+
1. Fork it
|
50
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
51
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
52
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
53
|
+
5. Create new Pull Request
|
data/docs/restore.md
CHANGED
@@ -2,10 +2,27 @@
|
|
2
2
|
|
3
3
|
# How does restore work?
|
4
4
|
|
5
|
+
Backed-up emails are pushed to the IMAP server.
|
6
|
+
If there are clashes, folders are renamed.
|
7
|
+
|
5
8
|
# What are all these 'INBOX.12345' files?
|
6
9
|
|
10
|
+
If, when the backup is launched, the IMAP server contains a folder with
|
11
|
+
the same name, but different history to the local backup, the local
|
12
|
+
emails cannot simply be added to the existing folder.
|
13
|
+
|
14
|
+
In this case, a numeric suffix is added to the **local** folder,
|
15
|
+
before it is restored.
|
16
|
+
|
17
|
+
In this way, old and new emails are kept separate.
|
18
|
+
|
7
19
|
# Will my email get overwritten?
|
8
20
|
|
21
|
+
No.
|
22
|
+
|
23
|
+
Emails are identified by folder and a specific email id. Any email that
|
24
|
+
is already on the server is skipped.
|
25
|
+
|
9
26
|
## How do I restore to a different service?
|
10
27
|
|
11
28
|
1. Run setup and add the new server, (but don't run any backups),
|
data/imap-backup.gemspec
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path("lib", __dir__))
|
2
2
|
require "imap/backup/version"
|
3
|
-
require "rake/file_list"
|
4
3
|
|
5
4
|
Gem::Specification.new do |gem|
|
6
5
|
gem.name = "imap-backup"
|
@@ -10,24 +9,22 @@ Gem::Specification.new do |gem|
|
|
10
9
|
gem.email = ["joe.g.yates@gmail.com"]
|
11
10
|
gem.homepage = "https://github.com/joeyates/imap-backup"
|
12
11
|
gem.licenses = ["MIT"]
|
12
|
+
gem.version = Imap::Backup::VERSION
|
13
13
|
|
14
|
-
# Build list of files manually, see also
|
15
|
-
# https://github.com/rubygems/rubygems/blob/master/bundler/bundler.gemspec#L37
|
16
14
|
gem.files = %w[bin/imap-backup]
|
17
|
-
gem.files += Dir.glob("docs
|
15
|
+
gem.files += Dir.glob("docs/*.md")
|
18
16
|
gem.files += Dir.glob("lib/**/*.rb")
|
19
|
-
gem.files += Dir.glob("spec/**/*{.rb,.yml}")
|
20
17
|
gem.files += %w[imap-backup.gemspec]
|
21
18
|
gem.files += %w[LICENSE README.md]
|
22
19
|
|
23
20
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
24
|
-
gem.test_files =
|
21
|
+
gem.test_files = Dir.glob("spec/**/*{.rb,.yml}")
|
25
22
|
gem.require_paths = ["lib"]
|
26
23
|
gem.required_ruby_version = ">= 2.5"
|
27
|
-
gem.version = Imap::Backup::VERSION
|
28
24
|
|
29
25
|
gem.add_runtime_dependency "highline"
|
30
26
|
gem.add_runtime_dependency "mail"
|
27
|
+
gem.add_runtime_dependency "os"
|
31
28
|
gem.add_runtime_dependency "rake"
|
32
29
|
gem.add_runtime_dependency "thor", "~> 1.1"
|
33
30
|
|
data/lib/email/mboxrd/message.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
require "forwardable"
|
1
2
|
require "mail"
|
2
3
|
|
3
4
|
module Email; end
|
4
5
|
|
5
6
|
module Email::Mboxrd
|
6
7
|
class Message
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :@parsed, :subject
|
10
|
+
|
7
11
|
attr_reader :supplied_body
|
8
12
|
|
9
13
|
def self.from_serialized(serialized)
|
@@ -36,12 +40,12 @@ module Email::Mboxrd
|
|
36
40
|
supplied_body.gsub(/(?<!\r)\n/, "\r\n")
|
37
41
|
end
|
38
42
|
|
43
|
+
private
|
44
|
+
|
39
45
|
def parsed
|
40
46
|
@parsed ||= Mail.new(supplied_body)
|
41
47
|
end
|
42
48
|
|
43
|
-
private
|
44
|
-
|
45
49
|
def from
|
46
50
|
@from ||=
|
47
51
|
begin
|
data/lib/email/provider.rb
CHANGED
@@ -1,37 +1,27 @@
|
|
1
|
+
require "email/provider/default"
|
2
|
+
require "email/provider/apple_mail"
|
3
|
+
require "email/provider/fastmail"
|
4
|
+
require "email/provider/gmail"
|
5
|
+
|
1
6
|
module Email; end
|
2
7
|
|
3
8
|
class Email::Provider
|
4
|
-
GMAIL_IMAP_SERVER = "imap.gmail.com".freeze
|
5
|
-
|
6
9
|
def self.for_address(address)
|
7
10
|
case
|
8
11
|
when address.end_with?("@fastmail.com")
|
9
|
-
new
|
10
|
-
when address.end_with?("@gmail.com")
|
11
|
-
new(:gmail)
|
12
|
+
Email::Provider::Fastmail.new
|
12
13
|
when address.end_with?("@fastmail.fm")
|
13
|
-
new
|
14
|
+
Email::Provider::Fastmail.new
|
15
|
+
when address.end_with?("@gmail.com")
|
16
|
+
Email::Provider::GMail.new
|
17
|
+
when address.end_with?("@icloud.com")
|
18
|
+
Email::Provider::AppleMail.new
|
19
|
+
when address.end_with?("@mac.com")
|
20
|
+
Email::Provider::AppleMail.new
|
21
|
+
when address.end_with?("@me.com")
|
22
|
+
Email::Provider::AppleMail.new
|
14
23
|
else
|
15
|
-
new
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_reader :provider
|
20
|
-
|
21
|
-
def initialize(provider)
|
22
|
-
@provider = provider
|
23
|
-
end
|
24
|
-
|
25
|
-
def options
|
26
|
-
{port: 993, ssl: {ssl_version: :TLSv1_2}}
|
27
|
-
end
|
28
|
-
|
29
|
-
def host
|
30
|
-
case provider
|
31
|
-
when :gmail
|
32
|
-
GMAIL_IMAP_SERVER
|
33
|
-
when :fastmail
|
34
|
-
"imap.fastmail.com"
|
24
|
+
Email::Provider::Default.new
|
35
25
|
end
|
36
26
|
end
|
37
27
|
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require "
|
1
|
+
require "imap/backup/client/apple_mail"
|
2
|
+
require "imap/backup/client/default"
|
2
3
|
|
3
4
|
require "retry_on_error"
|
4
5
|
|
@@ -29,17 +30,15 @@ module Imap::Backup
|
|
29
30
|
def folders
|
30
31
|
@folders ||=
|
31
32
|
begin
|
32
|
-
|
33
|
-
mailbox_lists = imap.list(root, "*")
|
33
|
+
folders = client.list
|
34
34
|
|
35
|
-
if
|
35
|
+
if folders.empty?
|
36
36
|
message = "Unable to get folder list for account #{username}"
|
37
37
|
Imap::Backup.logger.info message
|
38
38
|
raise message
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
utf7_encoded.map { |n| Net::IMAP.decode_utf7(n) }
|
41
|
+
folders
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
@@ -54,7 +53,7 @@ module Imap::Backup
|
|
54
53
|
def run_backup
|
55
54
|
Imap::Backup.logger.debug "Running backup of account: #{username}"
|
56
55
|
# start the connection so we get logging messages in the right order
|
57
|
-
|
56
|
+
client
|
58
57
|
each_folder do |folder, serializer|
|
59
58
|
next if !folder.exist?
|
60
59
|
|
@@ -89,34 +88,36 @@ module Imap::Backup
|
|
89
88
|
end
|
90
89
|
|
91
90
|
def disconnect
|
92
|
-
|
91
|
+
client.disconnect if @client
|
93
92
|
end
|
94
93
|
|
95
94
|
def reconnect
|
96
95
|
disconnect
|
97
|
-
@
|
96
|
+
@client = nil
|
98
97
|
end
|
99
98
|
|
100
|
-
def
|
101
|
-
@
|
99
|
+
def client
|
100
|
+
@client ||=
|
102
101
|
retry_on_error(errors: LOGIN_RETRY_CLASSES) do
|
103
102
|
options = provider_options
|
104
103
|
Imap::Backup.logger.debug(
|
105
104
|
"Creating IMAP instance: #{server}, options: #{options.inspect}"
|
106
105
|
)
|
107
|
-
|
106
|
+
client =
|
107
|
+
if provider.is_a?(Email::Provider::AppleMail)
|
108
|
+
Client::AppleMail.new(server, options)
|
109
|
+
else
|
110
|
+
Client::Default.new(server, options)
|
111
|
+
end
|
108
112
|
Imap::Backup.logger.debug "Logging in: #{username}/#{masked_password}"
|
109
|
-
|
113
|
+
client.login(username, password)
|
110
114
|
Imap::Backup.logger.debug "Login complete"
|
111
|
-
|
115
|
+
client
|
112
116
|
end
|
113
117
|
end
|
114
118
|
|
115
119
|
def server
|
116
|
-
|
117
|
-
return nil if provider.nil?
|
118
|
-
|
119
|
-
@server = provider.host
|
120
|
+
@server ||= provider.host
|
120
121
|
end
|
121
122
|
|
122
123
|
private
|
@@ -186,16 +187,5 @@ module Imap::Backup
|
|
186
187
|
def provider_options
|
187
188
|
provider.options.merge(connection_options)
|
188
189
|
end
|
189
|
-
|
190
|
-
# 6.3.8. LIST Command
|
191
|
-
# An empty ("" string) mailbox name argument is a special request to
|
192
|
-
# return the hierarchy delimiter and the root name of the name given
|
193
|
-
# in the reference.
|
194
|
-
def provider_root
|
195
|
-
return @provider_root if @provider_root
|
196
|
-
|
197
|
-
root_info = imap.list("", "")[0]
|
198
|
-
@provider_root = root_info.name
|
199
|
-
end
|
200
190
|
end
|
201
191
|
end
|
@@ -11,13 +11,13 @@ module Imap::Backup
|
|
11
11
|
extend Forwardable
|
12
12
|
include RetryOnError
|
13
13
|
|
14
|
-
|
14
|
+
BODY_ATTRIBUTE = "BODY[]".freeze
|
15
15
|
UID_FETCH_RETRY_CLASSES = [EOFError].freeze
|
16
16
|
|
17
17
|
attr_reader :connection
|
18
18
|
attr_reader :name
|
19
19
|
|
20
|
-
delegate
|
20
|
+
delegate client: :connection
|
21
21
|
|
22
22
|
def initialize(connection, name)
|
23
23
|
@connection = connection
|
@@ -40,20 +40,20 @@ module Imap::Backup
|
|
40
40
|
def create
|
41
41
|
return if exist?
|
42
42
|
|
43
|
-
|
43
|
+
client.create(utf7_encoded_name)
|
44
44
|
end
|
45
45
|
|
46
46
|
def uid_validity
|
47
47
|
@uid_validity ||=
|
48
48
|
begin
|
49
49
|
examine
|
50
|
-
|
50
|
+
client.responses["UIDVALIDITY"][-1]
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
def uids
|
55
55
|
examine
|
56
|
-
|
56
|
+
client.uid_search(["ALL"]).sort
|
57
57
|
rescue FolderNotFound
|
58
58
|
[]
|
59
59
|
rescue NoMethodError
|
@@ -72,15 +72,14 @@ module Imap::Backup
|
|
72
72
|
examine
|
73
73
|
fetch_data_items =
|
74
74
|
retry_on_error(errors: UID_FETCH_RETRY_CLASSES) do
|
75
|
-
|
75
|
+
client.uid_fetch([uid.to_i], [BODY_ATTRIBUTE])
|
76
76
|
end
|
77
77
|
return nil if fetch_data_items.nil?
|
78
78
|
|
79
79
|
fetch_data_item = fetch_data_items[0]
|
80
80
|
attributes = fetch_data_item.attr
|
81
|
-
return nil if !attributes.key?("RFC822")
|
82
81
|
|
83
|
-
attributes
|
82
|
+
attributes[BODY_ATTRIBUTE]
|
84
83
|
rescue FolderNotFound
|
85
84
|
nil
|
86
85
|
end
|
@@ -88,14 +87,14 @@ module Imap::Backup
|
|
88
87
|
def append(message)
|
89
88
|
body = message.imap_body
|
90
89
|
date = message.date&.to_time
|
91
|
-
response =
|
90
|
+
response = client.append(utf7_encoded_name, body, nil, date)
|
92
91
|
extract_uid(response)
|
93
92
|
end
|
94
93
|
|
95
94
|
private
|
96
95
|
|
97
96
|
def examine
|
98
|
-
|
97
|
+
client.examine(utf7_encoded_name)
|
99
98
|
rescue Net::IMAP::NoResponseError
|
100
99
|
Imap::Backup.logger.warn "Folder '#{name}' does not exist on server"
|
101
100
|
raise FolderNotFound, "Folder '#{name}' does not exist on server"
|
@@ -5,12 +5,25 @@ module Imap::Backup::CLI::Helpers
|
|
5
5
|
options.each.with_object({}) { |(k, v), acc| acc[k.intern] = v }
|
6
6
|
end
|
7
7
|
|
8
|
+
def account(email)
|
9
|
+
connections = Imap::Backup::Configuration::List.new
|
10
|
+
account = connections.accounts.find { |a| a[:username] == email }
|
11
|
+
raise "#{email} is not a configured account" if !account
|
12
|
+
|
13
|
+
account
|
14
|
+
end
|
15
|
+
|
16
|
+
def connection(email)
|
17
|
+
account = account(email)
|
18
|
+
|
19
|
+
Imap::Backup::Account::Connection.new(account)
|
20
|
+
end
|
21
|
+
|
8
22
|
def each_connection(names)
|
9
23
|
begin
|
10
24
|
connections = Imap::Backup::Configuration::List.new(names)
|
11
25
|
rescue Imap::Backup::ConfigurationNotFound
|
12
26
|
raise "imap-backup is not configured. Run `imap-backup setup`"
|
13
|
-
return
|
14
27
|
end
|
15
28
|
|
16
29
|
connections.each_connection do |connection|
|
@@ -6,49 +6,46 @@ module Imap::Backup
|
|
6
6
|
desc "accounts", "List locally backed-up accounts"
|
7
7
|
def accounts
|
8
8
|
connections = Imap::Backup::Configuration::List.new
|
9
|
-
connections.accounts.each { |a| puts a[:username] }
|
9
|
+
connections.accounts.each { |a| Kernel.puts a[:username] }
|
10
10
|
end
|
11
11
|
|
12
12
|
desc "folders EMAIL", "List account folders"
|
13
13
|
def folders(email)
|
14
|
-
|
15
|
-
account = connections.accounts.find { |a| a[:username] == email }
|
16
|
-
raise "#{email} is not a configured account" if !account
|
14
|
+
connection = connection(email)
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
puts %("#{f.name}")
|
16
|
+
connection.local_folders.each do |_s, f|
|
17
|
+
Kernel.puts %("#{f.name}")
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
21
|
desc "list EMAIL FOLDER", "List emails in a folder"
|
25
22
|
def list(email, folder_name)
|
26
|
-
|
27
|
-
account = connections.accounts.find { |a| a[:username] == email }
|
28
|
-
raise "#{email} is not a configured account" if !account
|
23
|
+
connection = connection(email)
|
29
24
|
|
30
|
-
|
31
|
-
folder_serializer, folder = account_connection.local_folders.find do |(_s, f)|
|
25
|
+
folder_serializer, _folder = connection.local_folders.find do |(_s, f)|
|
32
26
|
f.name == folder_name
|
33
27
|
end
|
34
28
|
raise "Folder '#{folder_name}' not found" if !folder_serializer
|
35
29
|
|
36
30
|
max_subject = 60
|
37
|
-
puts format(
|
38
|
-
|
31
|
+
Kernel.puts format(
|
32
|
+
"%-10<uid>s %-#{max_subject}<subject>s - %<date>s",
|
33
|
+
{uid: "UID", subject: "Subject", date: "Date"}
|
34
|
+
)
|
35
|
+
Kernel.puts "-" * (12 + max_subject + 28)
|
39
36
|
|
40
37
|
uids = folder_serializer.uids
|
41
38
|
|
42
39
|
folder_serializer.each_message(uids).map do |uid, message|
|
43
40
|
m = {
|
44
41
|
uid: uid,
|
45
|
-
date: message.
|
46
|
-
subject: message.
|
42
|
+
date: message.date.to_s,
|
43
|
+
subject: message.subject || ""
|
47
44
|
}
|
48
45
|
if m[:subject].length > max_subject
|
49
|
-
puts format("% 10<uid>u: %.#{max_subject - 3}<subject>s... - %<date>s", m)
|
46
|
+
Kernel.puts format("% 10<uid>u: %.#{max_subject - 3}<subject>s... - %<date>s", m)
|
50
47
|
else
|
51
|
-
puts format("% 10<uid>u: %-#{max_subject}<subject>s - %<date>s", m)
|
48
|
+
Kernel.puts format("% 10<uid>u: %-#{max_subject}<subject>s - %<date>s", m)
|
52
49
|
end
|
53
50
|
end
|
54
51
|
end
|
@@ -60,12 +57,9 @@ module Imap::Backup
|
|
60
57
|
the UID.
|
61
58
|
DESC
|
62
59
|
def show(email, folder_name, uids)
|
63
|
-
|
64
|
-
account = connections.accounts.find { |a| a[:username] == email }
|
65
|
-
raise "#{email} is not a configured account" if !account
|
60
|
+
connection = connection(email)
|
66
61
|
|
67
|
-
|
68
|
-
folder_serializer, _folder = account_connection.local_folders.find do |(_s, f)|
|
62
|
+
folder_serializer, _folder = connection.local_folders.find do |(_s, f)|
|
69
63
|
f.name == folder_name
|
70
64
|
end
|
71
65
|
raise "Folder '#{folder_name}' not found" if !folder_serializer
|
@@ -73,13 +67,13 @@ module Imap::Backup
|
|
73
67
|
uid_list = uids.split(",")
|
74
68
|
folder_serializer.each_message(uid_list).each do |uid, message|
|
75
69
|
if uid_list.count > 1
|
76
|
-
puts <<~HEADER
|
77
|
-
#{
|
78
|
-
#{format(
|
79
|
-
#{
|
70
|
+
Kernel.puts <<~HEADER
|
71
|
+
#{'-' * 80}
|
72
|
+
#{format('| UID: %-71s |', uid)}
|
73
|
+
#{'-' * 80}
|
80
74
|
HEADER
|
81
75
|
end
|
82
|
-
puts message.supplied_body
|
76
|
+
Kernel.puts message.supplied_body
|
83
77
|
end
|
84
78
|
end
|
85
79
|
end
|