imap-backup 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e4037b31fc56dcf88f312506ff2814b1c3fb516ae13cf9dbb4c8a772928b5fa
4
- data.tar.gz: 0465b9bf0b7a6a9dadc5c6c35b1a4dd65db058ab1ed37158d9fedf2dc093f777
3
+ metadata.gz: a62efa6b4c2e63180629e4a9770cf6b636eb48fa1aaad0177d7bab975ce3f251
4
+ data.tar.gz: ab0dee2784879df462e8fa1d622436b4a23f332dc731dd34ce353451a7164ce9
5
5
  SHA512:
6
- metadata.gz: 459620b79228707291d0b3be5037830e7100da42ecc920a1b5e19797fd1cc9aa9bc8fa667f5a5a7f89cc5d2647f47df5ae7e384a575c62a9bf4a13c25c70dd4b
7
- data.tar.gz: 8ac9d67819df8f957ffbc6a93be59aa401bdec704d75fa637c186012d2f15e23c3efa5c68ca8dc8918c97de3d90623ee5627d3cb8107615ee108e76588afd054
6
+ metadata.gz: ffe7443b8450980b05b170e8b4ed2d8cdaa093b17a60bf72c6c87c07e30752de1010aa444da3d4aea1b4348cbdd7b4fff0f2793e100f66de592796a8fa9885b6
7
+ data.tar.gz: 5779c9d8bc98070cba06a68c571b849cdb33fb994954f6f3cf320642d1d49023ab9db5c6f713db26c413703caf046745589a61e5d4cde2e2c6bce751e7d6f3a1
@@ -18,7 +18,7 @@ module Imap::Backup
18
18
  @username = options[:username]
19
19
  @password = options[:password]
20
20
  @local_path = options[:local_path]
21
- @backup_folders = options[:folders]
21
+ @config_folders = options[:folders]
22
22
  @server = options[:server]
23
23
  @connection_options = options[:connection_options] || {}
24
24
  @folders = nil
@@ -29,21 +29,24 @@ module Imap::Backup
29
29
  @folders ||=
30
30
  begin
31
31
  root = provider_root
32
- @folders = imap.list(root, "*")
33
- if @folders.nil?
34
- Imap::Backup.logger.warn(
35
- "Unable to get folder list for account #{username}"
36
- )
32
+ mailbox_lists = imap.list(root, "*")
33
+
34
+ if mailbox_lists.nil?
35
+ message = "Unable to get folder list for account #{username}"
36
+ Imap::Backup.logger.info message
37
+ raise message
37
38
  end
38
- @folders
39
+
40
+ utf7_encoded = mailbox_lists.map(&:name)
41
+ utf7_encoded.map { |n| Net::IMAP.decode_utf7(n) }
39
42
  end
40
43
  end
41
44
 
42
45
  def status
43
- backup_folders.map do |folder|
44
- f = Account::Folder.new(self, folder[:name])
45
- s = Serializer::Mbox.new(local_path, folder[:name])
46
- {name: folder[:name], local: s.uids, remote: f.uids}
46
+ backup_folders.map do |backup_folder|
47
+ f = Account::Folder.new(self, backup_folder[:name])
48
+ s = Serializer::Mbox.new(local_path, backup_folder[:name])
49
+ {name: backup_folder[:name], local: s.uids, remote: f.uids}
47
50
  end
48
51
  end
49
52
 
@@ -105,18 +108,12 @@ module Imap::Backup
105
108
  @server = provider.host
106
109
  end
107
110
 
108
- def backup_folders
109
- return @backup_folders if @backup_folders && !@backup_folders.empty?
110
-
111
- (folders || []).map { |f| {name: f.name} }
112
- end
113
-
114
111
  private
115
112
 
116
113
  def each_folder
117
- backup_folders.each do |folder_info|
118
- folder = Account::Folder.new(self, folder_info[:name])
119
- serializer = Serializer::Mbox.new(local_path, folder_info[:name])
114
+ backup_folders.each do |backup_folder|
115
+ folder = Account::Folder.new(self, backup_folder[:name])
116
+ serializer = Serializer::Mbox.new(local_path, backup_folder[:name])
120
117
  yield folder, serializer
121
118
  end
122
119
  end
@@ -175,6 +172,17 @@ module Imap::Backup
175
172
  end
176
173
  end
177
174
 
175
+ def backup_folders
176
+ @backup_folders ||=
177
+ begin
178
+ if @config_folders && @config_folders.any?
179
+ @config_folders
180
+ else
181
+ folders.map { |name| {name: name} }
182
+ end
183
+ end
184
+ end
185
+
178
186
  def provider
179
187
  @provider ||= Email::Provider.for_address(username)
180
188
  end
@@ -36,7 +36,7 @@ module Imap::Backup
36
36
  def create
37
37
  return if exist?
38
38
 
39
- imap.create(name)
39
+ imap.create(utf7_encoded_name)
40
40
  end
41
41
 
42
42
  def uid_validity
@@ -81,22 +81,27 @@ module Imap::Backup
81
81
  def append(message)
82
82
  body = message.imap_body
83
83
  date = message.date&.to_time
84
- response = imap.append(name, body, nil, date)
84
+ response = imap.append(utf7_encoded_name, body, nil, date)
85
85
  extract_uid(response)
86
86
  end
87
87
 
88
88
  private
89
89
 
90
90
  def examine
91
- imap.examine(name)
91
+ imap.examine(utf7_encoded_name)
92
92
  rescue Net::IMAP::NoResponseError
93
- Imap::Backup.logger.warn "Folder '#{name}' does not exist"
94
- raise FolderNotFound, "Folder '#{name}' does not exist"
93
+ Imap::Backup.logger.warn "Folder '#{name}' does not exist on server"
94
+ raise FolderNotFound, "Folder '#{name}' does not exist on server"
95
95
  end
96
96
 
97
97
  def extract_uid(response)
98
98
  @uid_validity, uid = response.data.code.data.split(" ").map(&:to_i)
99
99
  uid
100
100
  end
101
+
102
+ def utf7_encoded_name
103
+ @utf7_encoded_name ||=
104
+ Net::IMAP.encode_utf7(name).force_encoding("ASCII-8BIT")
105
+ end
101
106
  end
102
107
  end
@@ -15,7 +15,7 @@ module Imap::Backup
15
15
  return
16
16
  end
17
17
 
18
- if folders.nil?
18
+ if imap_folders.nil?
19
19
  Imap::Backup.logger.warn "Unable to get folder list"
20
20
  highline.ask "Press a key "
21
21
  return
@@ -44,29 +44,28 @@ module Imap::Backup
44
44
  end
45
45
 
46
46
  def add_folders(menu)
47
- folders.each do |folder|
48
- name = folder.name
49
- mark = selected?(name) ? "+" : "-"
50
- menu.choice("#{mark} #{name}") do
51
- toggle_selection name
47
+ imap_folders.each do |folder|
48
+ mark = selected?(folder) ? "+" : "-"
49
+ menu.choice("#{mark} #{folder}") do
50
+ toggle_selection folder
52
51
  end
53
52
  end
54
53
  end
55
54
 
56
55
  def selected?(folder_name)
57
- backup_folders = account[:folders]
58
- return false if backup_folders.nil?
56
+ config_folders = account[:folders]
57
+ return false if config_folders.nil?
59
58
 
60
- backup_folders.find { |f| f[:name] == folder_name }
59
+ config_folders.find { |f| f[:name] == folder_name }
61
60
  end
62
61
 
63
62
  def remove_missing
64
63
  removed = []
65
- backup_folders = []
64
+ config_folders = []
66
65
  account[:folders].each do |f|
67
- found = folders.find { |folder| folder.name == f[:name] }
66
+ found = imap_folders.find { |folder| folder == f[:name] }
68
67
  if found
69
- backup_folders << f
68
+ config_folders << f
70
69
  else
71
70
  removed << f[:name]
72
71
  end
@@ -74,7 +73,7 @@ module Imap::Backup
74
73
 
75
74
  return if removed.empty?
76
75
 
77
- account[:folders] = backup_folders
76
+ account[:folders] = config_folders
78
77
  account[:modified] = true
79
78
 
80
79
  Kernel.puts <<~MESSAGE
@@ -101,8 +100,8 @@ module Imap::Backup
101
100
  nil
102
101
  end
103
102
 
104
- def folders
105
- @folders ||= connection.folders
103
+ def imap_folders
104
+ @imap_folders ||= connection.folders
106
105
  end
107
106
 
108
107
  def highline
@@ -2,7 +2,7 @@ module Imap; end
2
2
 
3
3
  module Imap::Backup
4
4
  MAJOR = 3
5
- MINOR = 0
5
+ MINOR = 1
6
6
  REVISION = 0
7
7
  PRE = nil
8
8
  VERSION = [MAJOR, MINOR, REVISION, PRE].compact.map(&:to_s).join(".")
@@ -23,11 +23,11 @@ describe Imap::Backup::Account::Connection do
23
23
  username: USERNAME,
24
24
  password: PASSWORD,
25
25
  local_path: LOCAL_PATH,
26
- folders: backup_folders,
26
+ folders: config_folders,
27
27
  server: server
28
28
  }
29
29
  end
30
- let(:backup_folders) { [FOLDER_CONFIG] }
30
+ let(:config_folders) { [FOLDER_CONFIG] }
31
31
  let(:root_info) do
32
32
  instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)
33
33
  end
@@ -62,7 +62,6 @@ describe Imap::Backup::Account::Connection do
62
62
  [:username, USERNAME],
63
63
  [:password, PASSWORD],
64
64
  [:local_path, LOCAL_PATH],
65
- [:backup_folders, [FOLDER_CONFIG]],
66
65
  [:server, SERVER]
67
66
  ].each do |attr, expected|
68
67
  it "expects #{attr}" do
@@ -144,11 +143,21 @@ describe Imap::Backup::Account::Connection do
144
143
 
145
144
  describe "#folders" do
146
145
  let(:imap_folders) do
147
- [instance_double(Net::IMAP::MailboxList)]
146
+ [instance_double(Net::IMAP::MailboxList, name: BACKUP_FOLDER)]
148
147
  end
149
148
 
150
149
  it "returns the list of folders" do
151
- expect(subject.folders).to eq(imap_folders)
150
+ expect(subject.folders).to eq([BACKUP_FOLDER])
151
+ end
152
+
153
+ context "with non-ASCII folder names" do
154
+ let(:imap_folders) do
155
+ [instance_double(Net::IMAP::MailboxList, name: "Gel&APY-scht")]
156
+ end
157
+
158
+ it "converts them to UTF-8" do
159
+ expect(subject.folders).to eq(["Gelöscht"])
160
+ end
152
161
  end
153
162
  end
154
163
 
@@ -198,7 +207,7 @@ describe Imap::Backup::Account::Connection do
198
207
  with(LOCAL_PATH, BACKUP_FOLDER) { serializer }
199
208
  end
200
209
 
201
- context "with supplied backup_folders" do
210
+ context "with supplied config_folders" do
202
211
  it "runs the downloader" do
203
212
  expect(downloader).to receive(:run)
204
213
 
@@ -216,7 +225,7 @@ describe Imap::Backup::Account::Connection do
216
225
  end
217
226
  end
218
227
 
219
- context "without supplied backup_folders" do
228
+ context "without supplied config_folders" do
220
229
  let(:imap_folders) do
221
230
  [instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)]
222
231
  end
@@ -228,8 +237,8 @@ describe Imap::Backup::Account::Connection do
228
237
  with(LOCAL_PATH, ROOT_NAME) { serializer }
229
238
  end
230
239
 
231
- context "when supplied backup_folders is nil" do
232
- let(:backup_folders) { nil }
240
+ context "when supplied config_folders is nil" do
241
+ let(:config_folders) { nil }
233
242
 
234
243
  it "runs the downloader for each folder" do
235
244
  expect(downloader).to receive(:run).exactly(:once)
@@ -238,8 +247,8 @@ describe Imap::Backup::Account::Connection do
238
247
  end
239
248
  end
240
249
 
241
- context "when supplied backup_folders is an empty list" do
242
- let(:backup_folders) { [] }
250
+ context "when supplied config_folders is an empty list" do
251
+ let(:config_folders) { [] }
243
252
 
244
253
  it "runs the downloader for each folder" do
245
254
  expect(downloader).to receive(:run).exactly(:once)
@@ -249,11 +258,13 @@ describe Imap::Backup::Account::Connection do
249
258
  end
250
259
 
251
260
  context "when the imap server doesn't return folders" do
252
- let(:backup_folders) { nil }
261
+ let(:config_folders) { nil }
253
262
  let(:imap_folders) { nil }
254
263
 
255
- it "does not fail" do
256
- expect { subject.run_backup }.to_not raise_error
264
+ it "fails" do
265
+ expect do
266
+ subject.run_backup
267
+ end.to raise_error(RuntimeError, /Unable to get folder list/)
257
268
  end
258
269
  end
259
270
  end
@@ -1,7 +1,10 @@
1
1
  # rubocop:disable RSpec/PredicateMatcher
2
2
 
3
3
  describe Imap::Backup::Account::Folder do
4
- subject { described_class.new(connection, "my_folder") }
4
+ FOLDER_NAME = "Gelöscht"
5
+ ENCODED_FOLDER_NAME = "Gel&APY-scht"
6
+
7
+ subject { described_class.new(connection, FOLDER_NAME) }
5
8
 
6
9
  let(:imap) do
7
10
  instance_double(
@@ -16,7 +19,7 @@ describe Imap::Backup::Account::Folder do
16
19
  instance_double(Imap::Backup::Account::Connection, imap: imap)
17
20
  end
18
21
  let(:missing_mailbox_data) do
19
- OpenStruct.new(text: "Unknown Mailbox: my_folder")
22
+ OpenStruct.new(text: "Unknown Mailbox: #{FOLDER_NAME}")
20
23
  end
21
24
  let(:missing_mailbox_response) { OpenStruct.new(data: missing_mailbox_data) }
22
25
  let(:missing_mailbox_error) do
@@ -36,7 +39,8 @@ describe Imap::Backup::Account::Folder do
36
39
 
37
40
  context "with missing mailboxes" do
38
41
  before do
39
- allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
42
+ allow(imap).to receive(:examine).
43
+ with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
40
44
  end
41
45
 
42
46
  it "returns an empty array" do
@@ -50,7 +54,8 @@ describe Imap::Backup::Account::Folder do
50
54
  end
51
55
 
52
56
  before do
53
- allow(imap).to receive(:examine).and_raise(no_method_error)
57
+ allow(imap).to receive(:examine).
58
+ with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
54
59
  end
55
60
 
56
61
  it "returns an empty array" do
@@ -82,7 +87,8 @@ describe Imap::Backup::Account::Folder do
82
87
 
83
88
  context "when the mailbox doesn't exist" do
84
89
  before do
85
- allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
90
+ allow(imap).to receive(:examine).
91
+ with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
86
92
  end
87
93
 
88
94
  it "is nil" do
@@ -101,7 +107,7 @@ describe Imap::Backup::Account::Folder do
101
107
 
102
108
  describe "#folder" do
103
109
  it "is the name" do
104
- expect(subject.folder).to eq("my_folder")
110
+ expect(subject.folder).to eq(FOLDER_NAME)
105
111
  end
106
112
  end
107
113
 
@@ -114,7 +120,8 @@ describe Imap::Backup::Account::Folder do
114
120
 
115
121
  context "when the folder doesn't exist" do
116
122
  before do
117
- allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
123
+ allow(imap).to receive(:examine).
124
+ with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
118
125
  end
119
126
 
120
127
  it "is false" do
@@ -134,14 +141,21 @@ describe Imap::Backup::Account::Folder do
134
141
 
135
142
  context "when the folder doesn't exist" do
136
143
  before do
137
- allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
144
+ allow(imap).to receive(:examine).
145
+ with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
138
146
  end
139
147
 
140
- it "is does not create the folder" do
148
+ it "creates the folder" do
141
149
  expect(imap).to receive(:create)
142
150
 
143
151
  subject.create
144
152
  end
153
+
154
+ it "encodes the folder name" do
155
+ expect(imap).to receive(:create).with(ENCODED_FOLDER_NAME)
156
+
157
+ subject.create
158
+ end
145
159
  end
146
160
  end
147
161
 
@@ -154,7 +168,8 @@ describe Imap::Backup::Account::Folder do
154
168
 
155
169
  context "when the folder doesn't exist" do
156
170
  before do
157
- allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
171
+ allow(imap).to receive(:examine).
172
+ with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
158
173
  end
159
174
 
160
175
  it "raises an error" do
@@ -6,11 +6,11 @@ describe Imap::Backup::Configuration::FolderChooser do
6
6
 
7
7
  let(:connection) do
8
8
  instance_double(
9
- Imap::Backup::Account::Connection, folders: remote_folders
9
+ Imap::Backup::Account::Connection, folders: connection_folders
10
10
  )
11
11
  end
12
12
  let(:account) { {folders: []} }
13
- let(:remote_folders) { [] }
13
+ let(:connection_folders) { [] }
14
14
  let!(:highline_streams) { prepare_highline }
15
15
  let(:input) { highline_streams[0] }
16
16
  let(:output) { highline_streams[1] }
@@ -37,15 +37,9 @@ describe Imap::Backup::Configuration::FolderChooser do
37
37
 
38
38
  describe "folder listing" do
39
39
  let(:account) { {folders: [{name: "my_folder"}]} }
40
- let(:remote_folders) do
41
- # this one is already backed up:
42
- folder1 = instance_double(
43
- Imap::Backup::Account::Folder, name: "my_folder"
44
- )
45
- folder2 = instance_double(
46
- Imap::Backup::Account::Folder, name: "another_folder"
47
- )
48
- [folder1, folder2]
40
+ let(:connection_folders) do
41
+ # N.B. my_folder is already backed up
42
+ %w(my_folder another_folder)
49
43
  end
50
44
 
51
45
  describe "display" do
@@ -93,7 +87,7 @@ describe Imap::Backup::Configuration::FolderChooser do
93
87
  let(:account) do
94
88
  {folders: [{name: "on_server"}, {name: "not_on_server"}]}
95
89
  end
96
- let(:remote_folders) do
90
+ let(:connection_folders) do
97
91
  [
98
92
  instance_double(Imap::Backup::Account::Folder, name: "on_server")
99
93
  ]
@@ -112,7 +106,7 @@ describe Imap::Backup::Configuration::FolderChooser do
112
106
  end
113
107
 
114
108
  context "when folders are not available" do
115
- let(:remote_folders) { nil }
109
+ let(:connection_folders) { nil }
116
110
 
117
111
  before do
118
112
  allow(Imap::Backup::Configuration::Setup.highline).
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imap-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Yates