imap-backup 4.0.2 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/docs/development.md +1 -2
  4. data/imap-backup.gemspec +1 -0
  5. data/lib/email/provider/apple_mail.rb +7 -0
  6. data/lib/email/provider/default.rb +12 -0
  7. data/lib/email/provider/fastmail.rb +7 -0
  8. data/lib/email/provider/gmail.rb +7 -0
  9. data/lib/email/provider.rb +16 -26
  10. data/lib/imap/backup/account/connection.rb +19 -29
  11. data/lib/imap/backup/account/folder.rb +9 -10
  12. data/lib/imap/backup/cli/helpers.rb +1 -0
  13. data/lib/imap/backup/cli/local.rb +4 -1
  14. data/lib/imap/backup/cli/utils.rb +16 -5
  15. data/lib/imap/backup/client/apple_mail.rb +11 -0
  16. data/lib/imap/backup/client/default.rb +51 -0
  17. data/lib/imap/backup/configuration/account.rb +3 -1
  18. data/lib/imap/backup/configuration/connection_tester.rb +1 -1
  19. data/lib/imap/backup/configuration/store.rb +10 -5
  20. data/lib/imap/backup/downloader.rb +3 -4
  21. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +12 -25
  22. data/lib/imap/backup/version.rb +1 -1
  23. data/lib/thunderbird/install.rb +16 -0
  24. data/lib/thunderbird/local_folder.rb +33 -65
  25. data/lib/thunderbird/profiles.rb +18 -10
  26. data/lib/thunderbird/subdirectory.rb +96 -0
  27. data/lib/thunderbird/{local_folder_placeholder.rb → subdirectory_placeholder.rb} +4 -4
  28. data/lib/thunderbird.rb +10 -2
  29. data/spec/features/restore_spec.rb +1 -1
  30. data/spec/features/support/email_server.rb +2 -2
  31. data/spec/unit/email/provider/apple_mail_spec.rb +7 -0
  32. data/spec/unit/email/provider/default_spec.rb +17 -0
  33. data/spec/unit/email/provider/fastmail_spec.rb +7 -0
  34. data/spec/unit/email/provider/gmail_spec.rb +7 -0
  35. data/spec/unit/email/provider_spec.rb +12 -25
  36. data/spec/unit/imap/backup/account/connection_spec.rb +26 -51
  37. data/spec/unit/imap/backup/account/folder_spec.rb +22 -22
  38. data/spec/unit/imap/backup/cli/utils_spec.rb +2 -2
  39. data/spec/unit/imap/backup/client/default_spec.rb +22 -0
  40. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +3 -3
  41. data/spec/unit/imap/backup/configuration/store_spec.rb +25 -12
  42. data/spec/unit/imap/backup/downloader_spec.rb +1 -2
  43. metadata +57 -26
  44. data/lib/thunderbird/mailbox.rb +0 -25
@@ -6,9 +6,9 @@ describe Imap::Backup::Account::Folder do
6
6
 
7
7
  subject { described_class.new(connection, FOLDER_NAME) }
8
8
 
9
- let(:imap) do
9
+ let(:client) do
10
10
  instance_double(
11
- Net::IMAP,
11
+ Imap::Backup::Client::Default,
12
12
  append: append_response,
13
13
  create: nil,
14
14
  examine: nil,
@@ -16,7 +16,7 @@ describe Imap::Backup::Account::Folder do
16
16
  )
17
17
  end
18
18
  let(:connection) do
19
- instance_double(Imap::Backup::Account::Connection, imap: imap)
19
+ instance_double(Imap::Backup::Account::Connection, client: client)
20
20
  end
21
21
  let(:missing_mailbox_data) do
22
22
  OpenStruct.new(text: "Unknown Mailbox: #{FOLDER_NAME}")
@@ -31,7 +31,7 @@ describe Imap::Backup::Account::Folder do
31
31
  describe "#uids" do
32
32
  let(:uids) { [5678, 123] }
33
33
 
34
- before { allow(imap).to receive(:uid_search) { uids } }
34
+ before { allow(client).to receive(:uid_search) { uids } }
35
35
 
36
36
  it "lists available messages" do
37
37
  expect(subject.uids).to eq(uids.reverse)
@@ -39,7 +39,7 @@ describe Imap::Backup::Account::Folder do
39
39
 
40
40
  context "with missing mailboxes" do
41
41
  before do
42
- allow(imap).to receive(:examine).
42
+ allow(client).to receive(:examine).
43
43
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
44
44
  end
45
45
 
@@ -54,7 +54,7 @@ describe Imap::Backup::Account::Folder do
54
54
  end
55
55
 
56
56
  before do
57
- allow(imap).to receive(:examine).
57
+ allow(client).to receive(:examine).
58
58
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
59
59
  end
60
60
 
@@ -66,19 +66,19 @@ describe Imap::Backup::Account::Folder do
66
66
 
67
67
  describe "#fetch" do
68
68
  let(:message_body) { instance_double(String, force_encoding: nil) }
69
- let(:attributes) { {"RFC822" => message_body, "other" => "xxx"} }
69
+ let(:attributes) { {"BODY[]" => message_body, "other" => "xxx"} }
70
70
  let(:fetch_data_item) do
71
71
  instance_double(Net::IMAP::FetchData, attr: attributes)
72
72
  end
73
73
 
74
- before { allow(imap).to receive(:uid_fetch) { [fetch_data_item] } }
74
+ before { allow(client).to receive(:uid_fetch) { [fetch_data_item] } }
75
75
 
76
76
  it "returns the message" do
77
- expect(subject.fetch(123)).to eq(attributes)
77
+ expect(subject.fetch(123)).to eq(message_body)
78
78
  end
79
79
 
80
80
  context "when the server responds with nothing" do
81
- before { allow(imap).to receive(:uid_fetch) { nil } }
81
+ before { allow(client).to receive(:uid_fetch) { nil } }
82
82
 
83
83
  it "is nil" do
84
84
  expect(subject.fetch(123)).to be_nil
@@ -87,7 +87,7 @@ describe Imap::Backup::Account::Folder do
87
87
 
88
88
  context "when the mailbox doesn't exist" do
89
89
  before do
90
- allow(imap).to receive(:examine).
90
+ allow(client).to receive(:examine).
91
91
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
92
92
  end
93
93
 
@@ -96,7 +96,7 @@ describe Imap::Backup::Account::Folder do
96
96
  end
97
97
  end
98
98
 
99
- context "when the response doesn't have RFC822" do
99
+ context "when the response doesn't include 'BODY[]'" do
100
100
  let(:attributes) { {} }
101
101
 
102
102
  it "is nil" do
@@ -107,13 +107,13 @@ describe Imap::Backup::Account::Folder do
107
107
  context "when the first fetch_uid attempts fail" do
108
108
  before do
109
109
  outcomes = [-> { raise EOFError }, -> { [fetch_data_item] }]
110
- allow(imap).to receive(:uid_fetch) { outcomes.shift.call }
110
+ allow(client).to receive(:uid_fetch) { outcomes.shift.call }
111
111
  end
112
112
 
113
113
  it "retries" do
114
114
  subject.fetch(123)
115
115
 
116
- expect(imap).to have_received(:uid_fetch).twice
116
+ expect(client).to have_received(:uid_fetch).twice
117
117
  end
118
118
 
119
119
  it "succeeds" do
@@ -137,7 +137,7 @@ describe Imap::Backup::Account::Folder do
137
137
 
138
138
  context "when the folder doesn't exist" do
139
139
  before do
140
- allow(imap).to receive(:examine).
140
+ allow(client).to receive(:examine).
141
141
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
142
142
  end
143
143
 
@@ -150,7 +150,7 @@ describe Imap::Backup::Account::Folder do
150
150
  describe "#create" do
151
151
  context "when the folder exists" do
152
152
  it "is does not create the folder" do
153
- expect(imap).to_not receive(:create)
153
+ expect(client).to_not receive(:create)
154
154
 
155
155
  subject.create
156
156
  end
@@ -158,18 +158,18 @@ describe Imap::Backup::Account::Folder do
158
158
 
159
159
  context "when the folder doesn't exist" do
160
160
  before do
161
- allow(imap).to receive(:examine).
161
+ allow(client).to receive(:examine).
162
162
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
163
163
  end
164
164
 
165
165
  it "creates the folder" do
166
- expect(imap).to receive(:create)
166
+ expect(client).to receive(:create)
167
167
 
168
168
  subject.create
169
169
  end
170
170
 
171
171
  it "encodes the folder name" do
172
- expect(imap).to receive(:create).with(ENCODED_FOLDER_NAME)
172
+ expect(client).to receive(:create).with(ENCODED_FOLDER_NAME)
173
173
 
174
174
  subject.create
175
175
  end
@@ -185,7 +185,7 @@ describe Imap::Backup::Account::Folder do
185
185
 
186
186
  context "when the folder doesn't exist" do
187
187
  before do
188
- allow(imap).to receive(:examine).
188
+ allow(client).to receive(:examine).
189
189
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
190
190
  end
191
191
 
@@ -211,13 +211,13 @@ describe Imap::Backup::Account::Folder do
211
211
  end
212
212
 
213
213
  it "appends the message" do
214
- expect(imap).to receive(:append)
214
+ expect(client).to receive(:append)
215
215
 
216
216
  subject.append(message)
217
217
  end
218
218
 
219
219
  it "sets the date and time" do
220
- expect(imap).to receive(:append).
220
+ expect(client).to receive(:append).
221
221
  with(anything, anything, anything, message_date)
222
222
 
223
223
  subject.append(message)
@@ -16,13 +16,13 @@ describe Imap::Backup::CLI::Utils do
16
16
  exist?: true,
17
17
  name: "name",
18
18
  uid_validity: "uid_validity",
19
- uids: ["123", "456"]
19
+ uids: %w(123 456)
20
20
  )
21
21
  end
22
22
  let(:serializer) do
23
23
  instance_double(
24
24
  Imap::Backup::Serializer::Mbox,
25
- uids: ["123", "789"],
25
+ uids: %w(123 789),
26
26
  apply_uid_validity: nil,
27
27
  save: nil
28
28
  )
@@ -0,0 +1,22 @@
1
+ describe Imap::Backup::Client::Default do
2
+ subject { described_class.new("server", {}) }
3
+
4
+ let(:imap) { instance_double(Net::IMAP, list: imap_folders) }
5
+ let(:imap_folders) { [] }
6
+
7
+ before do
8
+ allow(Net::IMAP).to receive(:new) { imap }
9
+ end
10
+
11
+ describe "#list" do
12
+ context "with non-ASCII folder names" do
13
+ let(:imap_folders) do
14
+ [instance_double(Net::IMAP::MailboxList, name: "Gel&APY-scht")]
15
+ end
16
+
17
+ it "converts them to UTF-8" do
18
+ expect(subject.list).to eq(["Gelöscht"])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,7 +1,7 @@
1
1
  describe Imap::Backup::Configuration::ConnectionTester do
2
2
  describe ".test" do
3
3
  let(:connection) do
4
- instance_double(Imap::Backup::Account::Connection, imap: nil)
4
+ instance_double(Imap::Backup::Account::Connection, client: nil)
5
5
  end
6
6
 
7
7
  before do
@@ -10,7 +10,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
10
10
 
11
11
  describe "call" do
12
12
  it "tries to connect" do
13
- expect(connection).to receive(:imap)
13
+ expect(connection).to receive(:client)
14
14
 
15
15
  subject.test("foo")
16
16
  end
@@ -24,7 +24,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
24
24
 
25
25
  describe "failure" do
26
26
  before do
27
- allow(connection).to receive(:imap).and_raise(error)
27
+ allow(connection).to receive(:client).and_raise(error)
28
28
  end
29
29
 
30
30
  context "with no connection" do
@@ -1,4 +1,5 @@
1
1
  require "json"
2
+ require "os"
2
3
 
3
4
  # rubocop:disable RSpec/PredicateMatcher
4
5
 
@@ -189,10 +190,16 @@ describe Imap::Backup::Configuration::Store do
189
190
  end
190
191
 
191
192
  context "when file permissions are too open" do
192
- it "sets them to 0600" do
193
- expect(FileUtils).to receive(:chmod).with(0o600, file_path)
193
+ context "when on UNIX" do
194
+ before do
195
+ allow(OS).to receive(:windows?) { false }
196
+ end
194
197
 
195
- subject.save
198
+ it "sets them to 0600" do
199
+ expect(FileUtils).to receive(:chmod).with(0o600, file_path)
200
+
201
+ subject.save
202
+ end
196
203
  end
197
204
  end
198
205
 
@@ -206,18 +213,24 @@ describe Imap::Backup::Configuration::Store do
206
213
  end
207
214
  end
208
215
 
209
- context "when the config file permissions are too lax" do
210
- let(:file_exists) { true }
211
-
216
+ context "when on UNIX" do
212
217
  before do
213
- allow(Imap::Backup::Utils).to receive(:check_permissions).
214
- with(file_path, 0o600).and_raise("Error")
218
+ allow(OS).to receive(:windows?) { false }
215
219
  end
216
220
 
217
- it "fails" do
218
- expect do
219
- subject.save
220
- end.to raise_error(RuntimeError, "Error")
221
+ context "when the config file permissions are too lax" do
222
+ let(:file_exists) { true }
223
+
224
+ before do
225
+ allow(Imap::Backup::Utils).to receive(:check_permissions).
226
+ with(file_path, 0o600).and_raise("Error")
227
+ end
228
+
229
+ it "fails" do
230
+ expect do
231
+ subject.save
232
+ end.to raise_error(RuntimeError, "Error")
233
+ end
221
234
  end
222
235
  end
223
236
  end
@@ -3,11 +3,10 @@ describe Imap::Backup::Downloader do
3
3
  subject { described_class.new(folder, serializer) }
4
4
 
5
5
  let(:body) { "blah" }
6
- let(:message) { {"RFC822" => body} }
7
6
  let(:folder) do
8
7
  instance_double(
9
8
  Imap::Backup::Account::Folder,
10
- fetch: message,
9
+ fetch: body,
11
10
  name: "folder",
12
11
  uids: folder_uids
13
12
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imap-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.2
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-13 00:00:00.000000000 Z
11
+ date: 2021-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: os
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -167,6 +181,10 @@ files:
167
181
  - imap-backup.gemspec
168
182
  - lib/email/mboxrd/message.rb
169
183
  - lib/email/provider.rb
184
+ - lib/email/provider/apple_mail.rb
185
+ - lib/email/provider/default.rb
186
+ - lib/email/provider/fastmail.rb
187
+ - lib/email/provider/gmail.rb
170
188
  - lib/imap/backup.rb
171
189
  - lib/imap/backup/account/connection.rb
172
190
  - lib/imap/backup/account/folder.rb
@@ -179,6 +197,8 @@ files:
179
197
  - lib/imap/backup/cli/setup.rb
180
198
  - lib/imap/backup/cli/status.rb
181
199
  - lib/imap/backup/cli/utils.rb
200
+ - lib/imap/backup/client/apple_mail.rb
201
+ - lib/imap/backup/client/default.rb
182
202
  - lib/imap/backup/configuration/account.rb
183
203
  - lib/imap/backup/configuration/asker.rb
184
204
  - lib/imap/backup/configuration/connection_tester.rb
@@ -197,11 +217,12 @@ files:
197
217
  - lib/imap/backup/version.rb
198
218
  - lib/retry_on_error.rb
199
219
  - lib/thunderbird.rb
220
+ - lib/thunderbird/install.rb
200
221
  - lib/thunderbird/local_folder.rb
201
- - lib/thunderbird/local_folder_placeholder.rb
202
- - lib/thunderbird/mailbox.rb
203
222
  - lib/thunderbird/profile.rb
204
223
  - lib/thunderbird/profiles.rb
224
+ - lib/thunderbird/subdirectory.rb
225
+ - lib/thunderbird/subdirectory_placeholder.rb
205
226
  - spec/features/backup_spec.rb
206
227
  - spec/features/helper.rb
207
228
  - spec/features/restore_spec.rb
@@ -217,11 +238,16 @@ files:
217
238
  - spec/support/shared_examples/account_flagging.rb
218
239
  - spec/support/silence_logging.rb
219
240
  - spec/unit/email/mboxrd/message_spec.rb
241
+ - spec/unit/email/provider/apple_mail_spec.rb
242
+ - spec/unit/email/provider/default_spec.rb
243
+ - spec/unit/email/provider/fastmail_spec.rb
244
+ - spec/unit/email/provider/gmail_spec.rb
220
245
  - spec/unit/email/provider_spec.rb
221
246
  - spec/unit/imap/backup/account/connection_spec.rb
222
247
  - spec/unit/imap/backup/account/folder_spec.rb
223
248
  - spec/unit/imap/backup/cli/local_spec.rb
224
249
  - spec/unit/imap/backup/cli/utils_spec.rb
250
+ - spec/unit/imap/backup/client/default_spec.rb
225
251
  - spec/unit/imap/backup/configuration/account_spec.rb
226
252
  - spec/unit/imap/backup/configuration/asker_spec.rb
227
253
  - spec/unit/imap/backup/configuration/connection_tester_spec.rb
@@ -255,42 +281,47 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
281
  - !ruby/object:Gem::Version
256
282
  version: '0'
257
283
  requirements: []
258
- rubygems_version: 3.1.2
284
+ rubygems_version: 3.1.4
259
285
  signing_key:
260
286
  specification_version: 4
261
287
  summary: Backup GMail (or other IMAP) accounts to disk
262
288
  test_files:
263
289
  - spec/spec_helper.rb
264
- - spec/fixtures/connection.yml
265
- - spec/unit/email/provider_spec.rb
266
- - spec/unit/email/mboxrd/message_spec.rb
267
290
  - spec/unit/imap/backup_spec.rb
268
- - spec/unit/imap/backup/cli/utils_spec.rb
269
- - spec/unit/imap/backup/cli/local_spec.rb
270
- - spec/unit/imap/backup/utils_spec.rb
271
- - spec/unit/imap/backup/downloader_spec.rb
272
- - spec/unit/imap/backup/configuration/store_spec.rb
291
+ - spec/unit/imap/backup/configuration/account_spec.rb
292
+ - spec/unit/imap/backup/configuration/list_spec.rb
273
293
  - spec/unit/imap/backup/configuration/connection_tester_spec.rb
274
- - spec/unit/imap/backup/configuration/asker_spec.rb
275
294
  - spec/unit/imap/backup/configuration/setup_spec.rb
295
+ - spec/unit/imap/backup/configuration/asker_spec.rb
276
296
  - spec/unit/imap/backup/configuration/folder_chooser_spec.rb
277
- - spec/unit/imap/backup/configuration/account_spec.rb
278
- - spec/unit/imap/backup/configuration/list_spec.rb
279
- - spec/unit/imap/backup/account/folder_spec.rb
280
- - spec/unit/imap/backup/account/connection_spec.rb
297
+ - spec/unit/imap/backup/configuration/store_spec.rb
281
298
  - spec/unit/imap/backup/serializer/mbox_spec.rb
282
299
  - spec/unit/imap/backup/serializer/mbox_store_spec.rb
283
300
  - spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb
301
+ - spec/unit/imap/backup/cli/utils_spec.rb
302
+ - spec/unit/imap/backup/cli/local_spec.rb
303
+ - spec/unit/imap/backup/downloader_spec.rb
284
304
  - spec/unit/imap/backup/uploader_spec.rb
285
- - spec/support/fixtures.rb
286
- - spec/support/shared_examples/account_flagging.rb
287
- - spec/support/higline_test_helpers.rb
288
- - spec/support/silence_logging.rb
289
- - spec/gather_rspec_coverage.rb
305
+ - spec/unit/imap/backup/account/folder_spec.rb
306
+ - spec/unit/imap/backup/account/connection_spec.rb
307
+ - spec/unit/imap/backup/utils_spec.rb
308
+ - spec/unit/imap/backup/client/default_spec.rb
309
+ - spec/unit/email/mboxrd/message_spec.rb
310
+ - spec/unit/email/provider/gmail_spec.rb
311
+ - spec/unit/email/provider/default_spec.rb
312
+ - spec/unit/email/provider/apple_mail_spec.rb
313
+ - spec/unit/email/provider/fastmail_spec.rb
314
+ - spec/unit/email/provider_spec.rb
290
315
  - spec/features/backup_spec.rb
291
316
  - spec/features/helper.rb
317
+ - spec/features/restore_spec.rb
318
+ - spec/features/support/email_server.rb
292
319
  - spec/features/support/backup_directory.rb
293
- - spec/features/support/shared/message_fixtures.rb
294
320
  - spec/features/support/shared/connection_context.rb
295
- - spec/features/support/email_server.rb
296
- - spec/features/restore_spec.rb
321
+ - spec/features/support/shared/message_fixtures.rb
322
+ - spec/support/fixtures.rb
323
+ - spec/support/silence_logging.rb
324
+ - spec/support/higline_test_helpers.rb
325
+ - spec/support/shared_examples/account_flagging.rb
326
+ - spec/fixtures/connection.yml
327
+ - spec/gather_rspec_coverage.rb
@@ -1,25 +0,0 @@
1
- class Thunderbird::Mailbox
2
- attr_reader :local_folder
3
- attr_reader :name
4
-
5
- def initialize(local_folder, name)
6
- @local_folder = local_folder
7
- @name = name
8
- end
9
-
10
- def path
11
- File.join(local_folder.full_path, name)
12
- end
13
-
14
- def exists?
15
- File.exists?(path)
16
- end
17
-
18
- def msf_path
19
- path + ".msf"
20
- end
21
-
22
- def msf_exists?
23
- File.exists?(msf_path)
24
- end
25
- end