imap-backup 6.0.1 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|