imap-backup 6.0.1 → 6.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/email/provider/apple_mail.rb +4 -0
- data/lib/email/provider/base.rb +4 -0
- data/lib/email/provider/purelymail.rb +11 -0
- data/lib/email/provider.rb +3 -0
- data/lib/imap/backup/account/connection/client_factory.rb +1 -0
- data/lib/imap/backup/account/connection.rb +6 -2
- data/lib/imap/backup/account/folder.rb +22 -3
- data/lib/imap/backup/account.rb +9 -0
- data/lib/imap/backup/downloader.rb +28 -2
- data/lib/imap/backup/setup/account/header.rb +7 -1
- data/lib/imap/backup/setup/account.rb +14 -0
- data/lib/imap/backup/setup/backup_path.rb +5 -1
- data/lib/imap/backup/setup.rb +3 -3
- data/lib/imap/backup/version.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a05fedc57275cadd2a1bd22efbe88ef5ec6ee72843400499cac8b8df8e80c35
|
4
|
+
data.tar.gz: f0e8e859b5fb1bb8480730b3ea62abc7470f5d0ddb469113bbdac0e4f2a88d1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfb4de1a3048a9f29ee30fb56c7493524a7d688a6eab2ec3307005ba3c8d341a99c961acd1d8f588384dc91571b4528482931e52724df42dff19a26553568fb0
|
7
|
+
data.tar.gz: a411ad26b4ce3eb631c97d94c9242c1eb48fd57d23cffcec84f5c829d9354b506115b6c8278ee38430e27f0d6ca1400d55f74adce5eb99f94db2963f235c6d7a
|
data/lib/email/provider/base.rb
CHANGED
data/lib/email/provider.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "email/provider/apple_mail"
|
2
2
|
require "email/provider/fastmail"
|
3
3
|
require "email/provider/gmail"
|
4
|
+
require "email/provider/purelymail"
|
4
5
|
require "email/provider/unknown"
|
5
6
|
|
6
7
|
module Email; end
|
@@ -21,6 +22,8 @@ class Email::Provider
|
|
21
22
|
Email::Provider::AppleMail.new
|
22
23
|
when address.end_with?("@me.com")
|
23
24
|
Email::Provider::AppleMail.new
|
25
|
+
when address.end_with?("@purelymail.com")
|
26
|
+
Email::Provider::Purelymail.new
|
24
27
|
else
|
25
28
|
Email::Provider::Unknown.new
|
26
29
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require "email/provider"
|
2
1
|
require "imap/backup/client/apple_mail"
|
3
2
|
require "imap/backup/client/default"
|
4
3
|
require "imap/backup/account/connection/backup_folders"
|
@@ -46,7 +45,10 @@ module Imap::Backup
|
|
46
45
|
serializer.apply_uid_validity(folder.uid_validity)
|
47
46
|
begin
|
48
47
|
Downloader.new(
|
49
|
-
folder,
|
48
|
+
folder,
|
49
|
+
serializer,
|
50
|
+
multi_fetch_size: account.multi_fetch_size,
|
51
|
+
reset_seen_flags_after_fetch: account.reset_seen_flags_after_fetch
|
50
52
|
).run
|
51
53
|
rescue Net::IMAP::ByeResponseError
|
52
54
|
reconnect
|
@@ -105,6 +107,8 @@ module Imap::Backup
|
|
105
107
|
end
|
106
108
|
|
107
109
|
def ensure_account_folder
|
110
|
+
raise "The backup path for #{account.username} is not set" if !account.local_path
|
111
|
+
|
108
112
|
Utils.make_folder(
|
109
113
|
File.dirname(account.local_path),
|
110
114
|
File.basename(account.local_path),
|
@@ -98,14 +98,33 @@ module Imap::Backup
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
def
|
102
|
-
existing = uids
|
101
|
+
def set_flags(uids, flags)
|
103
102
|
# Use read-write access, via `select`
|
104
103
|
client.select(utf7_encoded_name)
|
105
|
-
client.uid_store(
|
104
|
+
client.uid_store(uids, "+FLAGS", flags)
|
105
|
+
end
|
106
|
+
|
107
|
+
def unset_flags(uids, flags)
|
108
|
+
client.select(utf7_encoded_name)
|
109
|
+
client.uid_store(uids, "-FLAGS", flags)
|
110
|
+
end
|
111
|
+
|
112
|
+
def clear
|
113
|
+
set_flags(uids, [:Deleted])
|
106
114
|
client.expunge
|
107
115
|
end
|
108
116
|
|
117
|
+
def unseen(uids)
|
118
|
+
messages = uids.map(&:to_s).join(",")
|
119
|
+
examine
|
120
|
+
client.uid_search([messages, "UNSEEN"])
|
121
|
+
rescue NoMethodError
|
122
|
+
# Apple Mail returns an empty response when searches have no results
|
123
|
+
[]
|
124
|
+
rescue FolderNotFound
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
109
128
|
private
|
110
129
|
|
111
130
|
def examine
|
data/lib/imap/backup/account.rb
CHANGED
@@ -8,6 +8,7 @@ module Imap::Backup
|
|
8
8
|
attr_reader :folders
|
9
9
|
attr_reader :server
|
10
10
|
attr_reader :connection_options
|
11
|
+
attr_reader :reset_seen_flags_after_fetch
|
11
12
|
attr_reader :changes
|
12
13
|
|
13
14
|
def initialize(options)
|
@@ -18,6 +19,7 @@ module Imap::Backup
|
|
18
19
|
@server = options[:server]
|
19
20
|
@connection_options = options[:connection_options]
|
20
21
|
@multi_fetch_size = options[:multi_fetch_size]
|
22
|
+
@reset_seen_flags_after_fetch = options[:reset_seen_flags_after_fetch]
|
21
23
|
@connection = nil
|
22
24
|
@changes = {}
|
23
25
|
@marked_for_deletion = false
|
@@ -54,6 +56,9 @@ module Imap::Backup
|
|
54
56
|
h[:server] = @server if @server
|
55
57
|
h[:connection_options] = @connection_options if @connection_options
|
56
58
|
h[:multi_fetch_size] = multi_fetch_size if @multi_fetch_size
|
59
|
+
if @reset_seen_flags_after_fetch
|
60
|
+
h[:reset_seen_flags_after_fetch] = @reset_seen_flags_after_fetch
|
61
|
+
end
|
57
62
|
h
|
58
63
|
end
|
59
64
|
|
@@ -99,6 +104,10 @@ module Imap::Backup
|
|
99
104
|
update(:multi_fetch_size, parsed)
|
100
105
|
end
|
101
106
|
|
107
|
+
def reset_seen_flags_after_fetch=(value)
|
108
|
+
update(:reset_seen_flags_after_fetch, value)
|
109
|
+
end
|
110
|
+
|
102
111
|
private
|
103
112
|
|
104
113
|
def update(field, value)
|
@@ -5,11 +5,21 @@ module Imap::Backup
|
|
5
5
|
attr_reader :folder
|
6
6
|
attr_reader :serializer
|
7
7
|
attr_reader :multi_fetch_size
|
8
|
+
# Some IMAP providers, notably Apple Mail, set the '\Seen' flag
|
9
|
+
# on emails when they are fetched. By setting `:reset_seen_flags_after_fetch`,
|
10
|
+
# a workaround is activated which checks which emails are 'unseen' before
|
11
|
+
# and after the fetch, and removes the '\Seen' flag from those which have changed.
|
12
|
+
# As this check is susceptible to 'race conditions', i.e. when a different
|
13
|
+
# client sets the '\Seen' flag while imap-backup is fetching, it is best
|
14
|
+
# to only use it when required (i.e. for IMAP providers which always
|
15
|
+
# mark messages as '\Seen' when accessed).
|
16
|
+
attr_reader :reset_seen_flags_after_fetch
|
8
17
|
|
9
|
-
def initialize(folder, serializer, multi_fetch_size: 1)
|
18
|
+
def initialize(folder, serializer, multi_fetch_size: 1, reset_seen_flags_after_fetch: false)
|
10
19
|
@folder = folder
|
11
20
|
@serializer = serializer
|
12
21
|
@multi_fetch_size = multi_fetch_size
|
22
|
+
@reset_seen_flags_after_fetch = reset_seen_flags_after_fetch
|
13
23
|
@uids = nil
|
14
24
|
end
|
15
25
|
|
@@ -30,7 +40,23 @@ module Imap::Backup
|
|
30
40
|
private
|
31
41
|
|
32
42
|
def download_block(block, index)
|
33
|
-
uids_and_bodies =
|
43
|
+
uids_and_bodies =
|
44
|
+
if reset_seen_flags_after_fetch
|
45
|
+
before_unseen = folder.unseen(block)
|
46
|
+
debug "Pre-fetch unseen messages: #{before_unseen.join(', ')}"
|
47
|
+
uids_and_bodies = folder.fetch_multi(block)
|
48
|
+
after_unseen = folder.unseen(block)
|
49
|
+
debug "Post-fetch unseen messages: #{after_unseen.join(', ')}"
|
50
|
+
changed = before_unseen - after_unseen
|
51
|
+
if changed.any?
|
52
|
+
ids = changed.join(", ")
|
53
|
+
debug "Removing '\Seen' flag for the following messages: #{ids}"
|
54
|
+
folder.unset_flags(changed, [:Seen])
|
55
|
+
end
|
56
|
+
uids_and_bodies
|
57
|
+
else
|
58
|
+
folder.fetch_multi(block)
|
59
|
+
end
|
34
60
|
if uids_and_bodies.nil?
|
35
61
|
if multi_fetch_size > 1
|
36
62
|
uids = block.join(", ")
|
@@ -21,7 +21,7 @@ module Imap::Backup
|
|
21
21
|
password#{space}#{masked_password}
|
22
22
|
path #{space}#{local_path}
|
23
23
|
folders #{space}#{folders.map { |f| f[:name] }.join(', ')}#{multi_fetch_size}
|
24
|
-
server #{space}#{account.server}#{connection_options}
|
24
|
+
server #{space}#{account.server}#{connection_options}#{reset_seen_flags_after_fetch}
|
25
25
|
|
26
26
|
Choose an action
|
27
27
|
HEADER
|
@@ -53,6 +53,12 @@ module Imap::Backup
|
|
53
53
|
"\nconnection options '#{escaped}'"
|
54
54
|
end
|
55
55
|
|
56
|
+
def reset_seen_flags_after_fetch
|
57
|
+
return nil if !account.reset_seen_flags_after_fetch
|
58
|
+
|
59
|
+
"\nchanges to unread flags will be reset during download"
|
60
|
+
end
|
61
|
+
|
56
62
|
def space
|
57
63
|
account.connection_options ? " " * 12 : " " * 4
|
58
64
|
end
|
@@ -37,6 +37,7 @@ module Imap::Backup
|
|
37
37
|
modify_multi_fetch_size menu
|
38
38
|
modify_server menu
|
39
39
|
modify_connection_options menu
|
40
|
+
toggle_reset_seen_flags_after_fetch menu
|
40
41
|
test_connection menu
|
41
42
|
delete_account menu
|
42
43
|
menu.choice("(q) return to main menu") { throw :done }
|
@@ -103,6 +104,19 @@ module Imap::Backup
|
|
103
104
|
end
|
104
105
|
end
|
105
106
|
|
107
|
+
def toggle_reset_seen_flags_after_fetch(menu)
|
108
|
+
menu_item =
|
109
|
+
if account.reset_seen_flags_after_fetch
|
110
|
+
"don't fix changes to unread flags during download"
|
111
|
+
else
|
112
|
+
"fix changes to unread flags during download"
|
113
|
+
end
|
114
|
+
new_value = account.reset_seen_flags_after_fetch ? nil : true
|
115
|
+
menu.choice(menu_item) do
|
116
|
+
account.reset_seen_flags_after_fetch = new_value
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
106
120
|
def test_connection(menu)
|
107
121
|
menu.choice("test connection") do
|
108
122
|
result = Setup::ConnectionTester.new(account).test
|
@@ -12,13 +12,17 @@ module Imap::Backup
|
|
12
12
|
|
13
13
|
def run
|
14
14
|
account.local_path = highline.ask("backup directory: ") do |q|
|
15
|
-
q.default = account.local_path
|
15
|
+
q.default = account.local_path || default
|
16
16
|
q.readline = true
|
17
17
|
q.validate = ->(path) { path_modification_validator(path) }
|
18
18
|
q.responses[:not_valid] = "Choose a different directory "
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def default
|
23
|
+
File.join(config.path, account.username.tr("@", "_"))
|
24
|
+
end
|
25
|
+
|
22
26
|
private
|
23
27
|
|
24
28
|
def highline
|
data/lib/imap/backup/setup.rb
CHANGED
@@ -80,11 +80,11 @@ module Imap::Backup
|
|
80
80
|
Imap::Backup::Account.new(
|
81
81
|
username: username,
|
82
82
|
password: "",
|
83
|
-
local_path: File.join(config.path, username.tr("@", "_")),
|
84
83
|
folders: []
|
85
84
|
).tap do |a|
|
86
|
-
|
87
|
-
a.server =
|
85
|
+
provider = ::Email::Provider.for_address(username)
|
86
|
+
a.server = provider.host if provider.host
|
87
|
+
a.reset_seen_flags_after_fetch = true if provider.sets_seen_flags_on_fetch?
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
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: 6.0
|
4
|
+
version: 6.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: 2022-07-
|
11
|
+
date: 2022-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -200,6 +200,7 @@ files:
|
|
200
200
|
- lib/email/provider/base.rb
|
201
201
|
- lib/email/provider/fastmail.rb
|
202
202
|
- lib/email/provider/gmail.rb
|
203
|
+
- lib/email/provider/purelymail.rb
|
203
204
|
- lib/email/provider/unknown.rb
|
204
205
|
- lib/imap/backup.rb
|
205
206
|
- lib/imap/backup/account.rb
|