imap-backup 16.0.0 → 16.1.0
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/lib/imap/backup/account/client_factory.rb +2 -26
- data/lib/imap/backup/account/folder.rb +3 -4
- data/lib/imap/backup/account.rb +1 -5
- data/lib/imap/backup/client/default.rb +31 -12
- data/lib/imap/backup/downloader.rb +19 -10
- data/lib/imap/backup/email/provider/apple_mail.rb +5 -0
- data/lib/imap/backup/email/provider/base.rb +11 -0
- data/lib/imap/backup/email/provider/gmail.rb +5 -0
- data/lib/imap/backup/version.rb +1 -1
- metadata +2 -3
- data/lib/imap/backup/client/apple_mail.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf6997d289ca5babbecd35e683ede921273300779f3f7dac95e247c0478f1814
|
4
|
+
data.tar.gz: '009892c47699a0cc94ff28c2d3ea7346915732b7dc86c7231b7e606302219888'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46bdbccf9be3efade25e500f6c67f37de4fc0a0aa8514b55f8eabf7e1171042b5be87d029f37d9cb449c23d1fcf0d5fd2a20c2e8595c6149eff0c20f89e6b3d3
|
7
|
+
data.tar.gz: d507a668897c325e2cc771d69b083f9929247b839b55d1fe86bfaeac3ee8be40df43b9f634d4f97c0188fe3bcbfba666456a9131236103455020fb45ecec9d61
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require "socket"
|
2
2
|
|
3
|
-
require "imap/backup/client/apple_mail"
|
4
3
|
require "imap/backup/client/automatic_login_wrapper"
|
5
4
|
require "imap/backup/client/default"
|
6
|
-
require "imap/backup/email/provider"
|
7
5
|
|
8
6
|
module Imap; end
|
9
7
|
|
@@ -14,39 +12,17 @@ module Imap::Backup
|
|
14
12
|
class Account::ClientFactory
|
15
13
|
def initialize(account:)
|
16
14
|
@account = account
|
17
|
-
@provider = nil
|
18
|
-
@server = nil
|
19
15
|
end
|
20
16
|
|
21
17
|
# @return [Client::AutomaticLoginWrapper] a client for the account
|
22
18
|
def run
|
23
|
-
|
24
|
-
|
25
|
-
"Creating IMAP instance: #{server}, options: #{options.inspect}"
|
26
|
-
)
|
27
|
-
client =
|
28
|
-
if provider.is_a?(Email::Provider::AppleMail)
|
29
|
-
Client::AppleMail.new(server, account, options)
|
30
|
-
else
|
31
|
-
Client::Default.new(server, account, options)
|
32
|
-
end
|
19
|
+
Logger.logger.debug("Creating IMAP instance")
|
20
|
+
client = Client::Default.new(account)
|
33
21
|
Client::AutomaticLoginWrapper.new(client: client)
|
34
22
|
end
|
35
23
|
|
36
24
|
private
|
37
25
|
|
38
26
|
attr_reader :account
|
39
|
-
|
40
|
-
def provider
|
41
|
-
@provider ||= Email::Provider.for_address(account.username)
|
42
|
-
end
|
43
|
-
|
44
|
-
def provider_options
|
45
|
-
provider.options.merge(account.connection_options || {})
|
46
|
-
end
|
47
|
-
|
48
|
-
def server
|
49
|
-
@server ||= account.server || provider.host
|
50
|
-
end
|
51
27
|
end
|
52
28
|
end
|
@@ -38,7 +38,6 @@ module Imap::Backup
|
|
38
38
|
Logger.logger.debug "Folder '#{name}' exists"
|
39
39
|
true
|
40
40
|
rescue FolderNotFound
|
41
|
-
Logger.logger.debug "Folder '#{name}' does not exist"
|
42
41
|
false
|
43
42
|
end
|
44
43
|
|
@@ -189,9 +188,9 @@ module Imap::Backup
|
|
189
188
|
def examine
|
190
189
|
client.examine(utf7_encoded_name)
|
191
190
|
rescue Net::IMAP::NoResponseError
|
192
|
-
|
193
|
-
Imap::Backup::Logger.logger.warn
|
194
|
-
raise FolderNotFound,
|
191
|
+
message = "Folder '#{name}' does not exist on server"
|
192
|
+
Imap::Backup::Logger.logger.warn message
|
193
|
+
raise FolderNotFound, message
|
195
194
|
end
|
196
195
|
|
197
196
|
def extract_uid(response)
|
data/lib/imap/backup/account.rb
CHANGED
@@ -211,11 +211,7 @@ module Imap::Backup
|
|
211
211
|
def multi_fetch_size
|
212
212
|
@multi_fetch_size ||= begin
|
213
213
|
int = @multi_fetch_size_orignal.to_i
|
214
|
-
|
215
|
-
int
|
216
|
-
else
|
217
|
-
DEFAULT_MULTI_FETCH_SIZE
|
218
|
-
end
|
214
|
+
int.positive? ? int : DEFAULT_MULTI_FETCH_SIZE
|
219
215
|
end
|
220
216
|
end
|
221
217
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "forwardable"
|
2
2
|
require "net/imap"
|
3
3
|
|
4
|
+
require "imap/backup/email/provider"
|
4
5
|
require "imap/backup/logger"
|
5
6
|
|
6
7
|
module Imap; end
|
@@ -17,10 +18,8 @@ module Imap::Backup
|
|
17
18
|
responses uid_fetch uid_search uid_store
|
18
19
|
)
|
19
20
|
|
20
|
-
def initialize(
|
21
|
+
def initialize(account)
|
21
22
|
@account = account
|
22
|
-
@options = options
|
23
|
-
@server = server
|
24
23
|
@state = nil
|
25
24
|
end
|
26
25
|
|
@@ -32,7 +31,10 @@ module Imap::Backup
|
|
32
31
|
|
33
32
|
return [] if mailbox_lists.nil?
|
34
33
|
|
35
|
-
|
34
|
+
ignored_tags = provider.folder_ignore_tags
|
35
|
+
mailbox_lists.
|
36
|
+
select { |ml| ml.attr & ignored_tags == [] }.
|
37
|
+
map { |ml| extract_name(ml) }
|
36
38
|
end
|
37
39
|
|
38
40
|
# Logs in to the account on the IMAP server
|
@@ -83,8 +85,6 @@ module Imap::Backup
|
|
83
85
|
private
|
84
86
|
|
85
87
|
attr_reader :account
|
86
|
-
attr_reader :options
|
87
|
-
attr_reader :server
|
88
88
|
attr_accessor :state
|
89
89
|
|
90
90
|
def imap
|
@@ -100,17 +100,36 @@ module Imap::Backup
|
|
100
100
|
account.password.gsub(/./, "x")
|
101
101
|
end
|
102
102
|
|
103
|
+
def provider
|
104
|
+
@provider ||= Email::Provider.for_address(account.username)
|
105
|
+
end
|
106
|
+
|
107
|
+
def options
|
108
|
+
@options ||= provider.options.merge(account.connection_options || {})
|
109
|
+
end
|
110
|
+
|
111
|
+
def server
|
112
|
+
@server ||= account.server || provider.host
|
113
|
+
end
|
114
|
+
|
103
115
|
# 6.3.8. LIST Command
|
104
116
|
# An empty ("" string) mailbox name argument is a special request to
|
105
117
|
# return the hierarchy delimiter and the root name of the name given
|
106
118
|
# in the reference.
|
107
119
|
def provider_root
|
108
|
-
@provider_root ||=
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
120
|
+
@provider_root ||=
|
121
|
+
if provider.root
|
122
|
+
Logger.logger.debug "Using fixed provider root '#{provider.root}'"
|
123
|
+
provider.root
|
124
|
+
else
|
125
|
+
Logger.logger.debug "Fetching provider root"
|
126
|
+
result = imap.list("", "")
|
127
|
+
raise "IMAP server did not return root folder for #{account.username}" if result.empty?
|
128
|
+
|
129
|
+
root_info = result[0]
|
130
|
+
Logger.logger.debug "Provider root is '#{root_info.name}'"
|
131
|
+
root_info.name
|
132
|
+
end
|
114
133
|
end
|
115
134
|
end
|
116
135
|
end
|
@@ -13,13 +13,15 @@ module Imap::Backup
|
|
13
13
|
@serializer = serializer
|
14
14
|
@multi_fetch_size = multi_fetch_size
|
15
15
|
@reset_seen_flags_after_fetch = reset_seen_flags_after_fetch
|
16
|
+
@folder_uids = nil
|
17
|
+
@serializer_uids = nil
|
16
18
|
@uids = nil
|
17
19
|
end
|
18
20
|
|
19
21
|
# Runs the downloader
|
20
22
|
# @return [void]
|
21
23
|
def run
|
22
|
-
debug("#{serializer_uids.count}
|
24
|
+
debug("#{serializer_uids.count} messages already downloaded")
|
23
25
|
debug("#{folder_uids.count} messages on server")
|
24
26
|
local_only_count = (serializer_uids - folder_uids).count
|
25
27
|
if local_only_count.positive?
|
@@ -33,15 +35,7 @@ module Imap::Backup
|
|
33
35
|
|
34
36
|
info("#{uids.count} new messages")
|
35
37
|
|
36
|
-
|
37
|
-
multifetch_failed = download_block(block, i)
|
38
|
-
raise MultiFetchFailedError if multifetch_failed
|
39
|
-
end
|
40
|
-
rescue MultiFetchFailedError
|
41
|
-
@count = nil
|
42
|
-
@multi_fetch_size = 1
|
43
|
-
@uids = nil
|
44
|
-
retry
|
38
|
+
download
|
45
39
|
rescue Net::IMAP::ByeResponseError
|
46
40
|
folder.client.reconnect
|
47
41
|
retry
|
@@ -54,6 +48,21 @@ module Imap::Backup
|
|
54
48
|
attr_reader :multi_fetch_size
|
55
49
|
attr_reader :reset_seen_flags_after_fetch
|
56
50
|
|
51
|
+
def download
|
52
|
+
block_count = (uids.count / multi_fetch_size.to_f).ceil
|
53
|
+
uids.each_slice(multi_fetch_size).with_index do |block, i|
|
54
|
+
debug("Downloading #{block.count} messages (block #{i + 1}/#{block_count})")
|
55
|
+
multifetch_failed = download_block(block, i)
|
56
|
+
raise MultiFetchFailedError if multifetch_failed
|
57
|
+
end
|
58
|
+
rescue MultiFetchFailedError
|
59
|
+
@multi_fetch_size = 1
|
60
|
+
@uids = nil
|
61
|
+
@folder_uids = nil
|
62
|
+
@serializer_uids = nil
|
63
|
+
retry
|
64
|
+
end
|
65
|
+
|
57
66
|
def download_block(block, index)
|
58
67
|
uids_and_bodies =
|
59
68
|
if reset_seen_flags_after_fetch
|
@@ -6,11 +6,22 @@ module Imap::Backup
|
|
6
6
|
|
7
7
|
# Supplies defaults for email provider behaviour
|
8
8
|
class Email::Provider::Base
|
9
|
+
# @return [Array<Symbol>] tags to ignore when listing folders
|
10
|
+
def folder_ignore_tags
|
11
|
+
[]
|
12
|
+
end
|
13
|
+
|
9
14
|
# @return [Hash] defaults for the Net::IMAP connection
|
10
15
|
def options
|
11
16
|
{port: 993, ssl: {min_version: OpenSSL::SSL::TLS1_2_VERSION}}
|
12
17
|
end
|
13
18
|
|
19
|
+
# By default, we query the server for this value.
|
20
|
+
# It is only fixed for Apple Mail accounts.
|
21
|
+
# @return [String, nil] any fixed value to use when requesting the list of account folders
|
22
|
+
def root
|
23
|
+
end
|
24
|
+
|
14
25
|
def sets_seen_flags_on_fetch?
|
15
26
|
false
|
16
27
|
end
|
@@ -5,6 +5,11 @@ module Imap; end
|
|
5
5
|
module Imap::Backup
|
6
6
|
# Provides overrides for GMail accounts
|
7
7
|
class Email::Provider::GMail < Email::Provider::Base
|
8
|
+
# https://imap-use.u.washington.narkive.com/RYMsOHTN/imap-protocol-status-on-a-noselect-mailbox
|
9
|
+
def folder_ignore_tags
|
10
|
+
[:Noselect]
|
11
|
+
end
|
12
|
+
|
8
13
|
# @return [String] the GMail IMAP server host name
|
9
14
|
def host
|
10
15
|
"imap.gmail.com"
|
data/lib/imap/backup/version.rb
CHANGED
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: 16.
|
4
|
+
version: 16.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Yates
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -192,7 +192,6 @@ files:
|
|
192
192
|
- lib/imap/backup/cli/stats.rb
|
193
193
|
- lib/imap/backup/cli/transfer.rb
|
194
194
|
- lib/imap/backup/cli/utils.rb
|
195
|
-
- lib/imap/backup/client/apple_mail.rb
|
196
195
|
- lib/imap/backup/client/automatic_login_wrapper.rb
|
197
196
|
- lib/imap/backup/client/default.rb
|
198
197
|
- lib/imap/backup/configuration.rb
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require "imap/backup/client/default"
|
2
|
-
|
3
|
-
module Imap; end
|
4
|
-
|
5
|
-
module Imap::Backup
|
6
|
-
# Overrides default IMAP client behaviour for Apple Mail accounts
|
7
|
-
class Client::AppleMail < Client::Default
|
8
|
-
# With Apple Mails's IMAP, passing "/" to list
|
9
|
-
# results in an empty list
|
10
|
-
# @return [String] the value to use when requesting the list of account folders
|
11
|
-
def provider_root
|
12
|
-
""
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|