imap-backup 6.0.0.rc2 → 6.0.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/imap-backup.gemspec +5 -1
- data/lib/cli_coverage.rb +11 -11
- data/lib/email/provider/base.rb +2 -0
- data/lib/email/provider/unknown.rb +2 -0
- data/lib/email/provider.rb +2 -0
- data/lib/imap/backup/account/connection/backup_folders.rb +27 -0
- data/lib/imap/backup/account/connection/client_factory.rb +54 -0
- data/lib/imap/backup/account/connection/folder_names.rb +26 -0
- data/lib/imap/backup/account/connection.rb +11 -95
- data/lib/imap/backup/account/folder.rb +9 -6
- data/lib/imap/backup/account.rb +3 -5
- data/lib/imap/backup/cli/backup.rb +1 -3
- data/lib/imap/backup/cli/helpers.rb +24 -22
- data/lib/imap/backup/cli/local.rb +20 -13
- data/lib/imap/backup/cli/migrate.rb +4 -10
- data/lib/imap/backup/cli/restore.rb +8 -7
- data/lib/imap/backup/cli/setup.rb +10 -8
- data/lib/imap/backup/cli/stats.rb +78 -0
- data/lib/imap/backup/cli/status.rb +2 -2
- data/lib/imap/backup/cli/utils.rb +4 -6
- data/lib/imap/backup/cli.rb +24 -3
- data/lib/imap/backup/configuration.rb +9 -11
- data/lib/imap/backup/downloader.rb +48 -30
- data/lib/imap/backup/migrator.rb +5 -5
- data/lib/imap/backup/sanitizer.rb +3 -2
- data/lib/imap/backup/serializer/appender.rb +49 -0
- data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
- data/lib/imap/backup/serializer/unused_name_finder.rb +27 -0
- data/lib/imap/backup/serializer.rb +24 -78
- data/lib/imap/backup/setup/account/header.rb +75 -0
- data/lib/imap/backup/setup/account.rb +14 -91
- data/lib/imap/backup/setup/asker.rb +4 -15
- data/lib/imap/backup/setup/backup_path.rb +41 -0
- data/lib/imap/backup/setup/email.rb +45 -0
- data/lib/imap/backup/setup/folder_chooser.rb +3 -3
- data/lib/imap/backup/setup/helpers.rb +1 -1
- data/lib/imap/backup/setup.rb +5 -4
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +39 -20
- data/lib/imap/backup/uploader.rb +46 -8
- data/lib/imap/backup/utils.rb +1 -1
- data/lib/imap/backup/version.rb +1 -1
- data/lib/imap/backup.rb +0 -1
- metadata +31 -134
- data/spec/features/backup_spec.rb +0 -100
- data/spec/features/configuration/minimal_configuration.rb +0 -15
- data/spec/features/configuration/missing_configuration.rb +0 -14
- data/spec/features/folders_spec.rb +0 -36
- data/spec/features/helper.rb +0 -2
- data/spec/features/local/list_accounts_spec.rb +0 -12
- data/spec/features/local/list_emails_spec.rb +0 -21
- data/spec/features/local/list_folders_spec.rb +0 -21
- data/spec/features/local/show_an_email_spec.rb +0 -34
- data/spec/features/migrate_spec.rb +0 -35
- data/spec/features/remote/list_account_folders_spec.rb +0 -16
- data/spec/features/restore_spec.rb +0 -162
- data/spec/features/status_spec.rb +0 -43
- data/spec/features/support/aruba.rb +0 -78
- data/spec/features/support/backup_directory.rb +0 -43
- data/spec/features/support/email_server.rb +0 -110
- data/spec/features/support/shared/connection_context.rb +0 -14
- data/spec/features/support/shared/message_fixtures.rb +0 -16
- data/spec/fixtures/connection.yml +0 -7
- data/spec/spec_helper.rb +0 -15
- data/spec/support/fixtures.rb +0 -11
- data/spec/support/higline_test_helpers.rb +0 -8
- data/spec/support/silence_logging.rb +0 -7
- data/spec/unit/email/mboxrd/message_spec.rb +0 -177
- data/spec/unit/email/provider/apple_mail_spec.rb +0 -7
- data/spec/unit/email/provider/base_spec.rb +0 -11
- data/spec/unit/email/provider/fastmail_spec.rb +0 -7
- data/spec/unit/email/provider/gmail_spec.rb +0 -7
- data/spec/unit/email/provider_spec.rb +0 -27
- data/spec/unit/imap/backup/account/connection_spec.rb +0 -433
- data/spec/unit/imap/backup/account/folder_spec.rb +0 -261
- data/spec/unit/imap/backup/account_spec.rb +0 -246
- data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -58
- data/spec/unit/imap/backup/cli/backup_spec.rb +0 -19
- data/spec/unit/imap/backup/cli/folders_spec.rb +0 -39
- data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
- data/spec/unit/imap/backup/cli/local_spec.rb +0 -100
- data/spec/unit/imap/backup/cli/migrate_spec.rb +0 -80
- data/spec/unit/imap/backup/cli/restore_spec.rb +0 -67
- data/spec/unit/imap/backup/cli/setup_spec.rb +0 -17
- data/spec/unit/imap/backup/cli/utils_spec.rb +0 -125
- data/spec/unit/imap/backup/cli_spec.rb +0 -93
- data/spec/unit/imap/backup/client/apple_mail_spec.rb +0 -9
- data/spec/unit/imap/backup/client/default_spec.rb +0 -22
- data/spec/unit/imap/backup/configuration_spec.rb +0 -238
- data/spec/unit/imap/backup/downloader_spec.rb +0 -96
- data/spec/unit/imap/backup/logger_spec.rb +0 -48
- data/spec/unit/imap/backup/migrator_spec.rb +0 -58
- data/spec/unit/imap/backup/sanitizer_spec.rb +0 -42
- data/spec/unit/imap/backup/serializer/directory_spec.rb +0 -37
- data/spec/unit/imap/backup/serializer/imap_spec.rb +0 -218
- data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +0 -45
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -101
- data/spec/unit/imap/backup/serializer_spec.rb +0 -296
- data/spec/unit/imap/backup/setup/account_spec.rb +0 -461
- data/spec/unit/imap/backup/setup/asker_spec.rb +0 -137
- data/spec/unit/imap/backup/setup/connection_tester_spec.rb +0 -51
- data/spec/unit/imap/backup/setup/folder_chooser_spec.rb +0 -146
- data/spec/unit/imap/backup/setup/helpers_spec.rb +0 -15
- data/spec/unit/imap/backup/setup_spec.rb +0 -301
- data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +0 -116
- data/spec/unit/imap/backup/uploader_spec.rb +0 -54
- data/spec/unit/imap/backup/utils_spec.rb +0 -92
- data/spec/unit/retry_on_error_spec.rb +0 -34
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require "imap/backup/setup/helpers"
|
|
2
|
+
|
|
3
|
+
module Imap::Backup
|
|
4
|
+
class Setup; end
|
|
5
|
+
class Setup::Account; end
|
|
6
|
+
|
|
7
|
+
class Setup::Account::Header
|
|
8
|
+
attr_reader :account
|
|
9
|
+
attr_reader :menu
|
|
10
|
+
|
|
11
|
+
def initialize(menu:, account:)
|
|
12
|
+
@menu = menu
|
|
13
|
+
@account = account
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def run
|
|
17
|
+
menu.header = <<~HEADER.chomp
|
|
18
|
+
#{helpers.title_prefix} Account#{modified_flag}
|
|
19
|
+
|
|
20
|
+
email #{space}#{account.username}
|
|
21
|
+
password#{space}#{masked_password}
|
|
22
|
+
path #{space}#{local_path}
|
|
23
|
+
folders #{space}#{folders.map { |f| f[:name] }.join(', ')}#{multi_fetch_size}
|
|
24
|
+
server #{space}#{account.server}#{connection_options}
|
|
25
|
+
|
|
26
|
+
Choose an action
|
|
27
|
+
HEADER
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def folders
|
|
33
|
+
account.folders || []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def helpers
|
|
37
|
+
Setup::Helpers.new
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def modified_flag
|
|
41
|
+
account.modified? ? "*" : ""
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def multi_fetch_size
|
|
45
|
+
"\nmulti-fetch #{account.multi_fetch_size}" if account.multi_fetch_size > 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def connection_options
|
|
49
|
+
return nil if !account.connection_options
|
|
50
|
+
|
|
51
|
+
escaped = JSON.generate(account.connection_options)
|
|
52
|
+
escaped.gsub!('"', '\"')
|
|
53
|
+
"\nconnection options '#{escaped}'"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def space
|
|
57
|
+
account.connection_options ? " " * 12 : " " * 4
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def masked_password
|
|
61
|
+
if (account.password == "") || account.password.nil?
|
|
62
|
+
"(unset)"
|
|
63
|
+
else
|
|
64
|
+
account.password.gsub(/./, "x")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def local_path
|
|
69
|
+
# In order to handle backslashes, as Highline effectively
|
|
70
|
+
# does an eval (!) on its templates, we need to doubly
|
|
71
|
+
# escape them
|
|
72
|
+
account.local_path.gsub("\\", "\\\\\\\\")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
require "imap/backup/setup/
|
|
1
|
+
require "imap/backup/setup/account/header"
|
|
2
|
+
require "imap/backup/setup/backup_path"
|
|
3
|
+
require "imap/backup/setup/email"
|
|
2
4
|
|
|
3
5
|
module Imap::Backup
|
|
4
6
|
class Setup; end
|
|
5
7
|
|
|
6
|
-
Setup::Account
|
|
8
|
+
class Setup::Account
|
|
9
|
+
attr_reader :account
|
|
10
|
+
attr_reader :config
|
|
11
|
+
attr_reader :highline
|
|
12
|
+
|
|
7
13
|
def initialize(config, account, highline)
|
|
8
|
-
|
|
14
|
+
@account = account
|
|
15
|
+
@config = config
|
|
16
|
+
@highline = highline
|
|
9
17
|
end
|
|
10
18
|
|
|
11
19
|
def run
|
|
@@ -37,54 +45,12 @@ module Imap::Backup
|
|
|
37
45
|
end
|
|
38
46
|
|
|
39
47
|
def header(menu)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if account.multi_fetch_size > 1
|
|
43
|
-
multi_fetch_size = "\nmulti-fetch #{account.multi_fetch_size}"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
if account.connection_options
|
|
47
|
-
escaped =
|
|
48
|
-
JSON.generate(account.connection_options)
|
|
49
|
-
connection_options =
|
|
50
|
-
"\nconnection options '#{escaped}'"
|
|
51
|
-
space = " " * 12
|
|
52
|
-
else
|
|
53
|
-
connection_options = nil
|
|
54
|
-
space = " " * 4
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
menu.header = <<~HEADER.chomp
|
|
58
|
-
#{helpers.title_prefix} Account#{modified}
|
|
59
|
-
|
|
60
|
-
email #{space}#{account.username}
|
|
61
|
-
password#{space}#{masked_password}
|
|
62
|
-
path #{space}#{account.local_path}
|
|
63
|
-
folders #{space}#{folders.map { |f| f[:name] }.join(', ')}#{multi_fetch_size}
|
|
64
|
-
server #{space}#{account.server}#{connection_options}
|
|
65
|
-
|
|
66
|
-
Choose an action
|
|
67
|
-
HEADER
|
|
48
|
+
Setup::Account::Header.new(menu: menu, account: account).run
|
|
68
49
|
end
|
|
69
50
|
|
|
70
51
|
def modify_email(menu)
|
|
71
52
|
menu.choice("modify email") do
|
|
72
|
-
|
|
73
|
-
Kernel.puts "username: #{username}"
|
|
74
|
-
other_accounts = config.accounts.reject { |a| a == account }
|
|
75
|
-
others = other_accounts.map { |a| a.username }
|
|
76
|
-
Kernel.puts "others: #{others.inspect}"
|
|
77
|
-
if others.include?(username)
|
|
78
|
-
Kernel.puts(
|
|
79
|
-
"There is already an account set up with that email address"
|
|
80
|
-
)
|
|
81
|
-
else
|
|
82
|
-
account.username = username
|
|
83
|
-
default = default_server(username)
|
|
84
|
-
if default && (account.server.nil? || (account.server == ""))
|
|
85
|
-
account.server = default
|
|
86
|
-
end
|
|
87
|
-
end
|
|
53
|
+
Setup::Email.new(account: account, config: config).run
|
|
88
54
|
end
|
|
89
55
|
end
|
|
90
56
|
|
|
@@ -96,25 +62,9 @@ module Imap::Backup
|
|
|
96
62
|
end
|
|
97
63
|
end
|
|
98
64
|
|
|
99
|
-
def path_modification_validator(path)
|
|
100
|
-
same = config.accounts.find do |a|
|
|
101
|
-
a.username != account.username && a.local_path == path
|
|
102
|
-
end
|
|
103
|
-
if same
|
|
104
|
-
Kernel.puts "The path '#{path}' is used to backup " \
|
|
105
|
-
"the account '#{same.username}'"
|
|
106
|
-
false
|
|
107
|
-
else
|
|
108
|
-
true
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
65
|
def modify_backup_path(menu)
|
|
113
66
|
menu.choice("modify backup path") do
|
|
114
|
-
|
|
115
|
-
account.local_path = Setup::Asker.backup_path(
|
|
116
|
-
account.local_path, ->(path) { path_modification_validator(path) }
|
|
117
|
-
)
|
|
67
|
+
Setup::BackupPath.new(account: account, config: config).run
|
|
118
68
|
end
|
|
119
69
|
end
|
|
120
70
|
|
|
@@ -169,32 +119,5 @@ module Imap::Backup
|
|
|
169
119
|
end
|
|
170
120
|
end
|
|
171
121
|
end
|
|
172
|
-
|
|
173
|
-
def folders
|
|
174
|
-
account.folders || []
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def masked_password
|
|
178
|
-
if (account.password == "") || account.password.nil?
|
|
179
|
-
"(unset)"
|
|
180
|
-
else
|
|
181
|
-
account.password.gsub(/./, "x")
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def default_server(username)
|
|
186
|
-
provider = Email::Provider.for_address(username)
|
|
187
|
-
|
|
188
|
-
if provider.is_a?(Email::Provider::Unknown)
|
|
189
|
-
Kernel.puts "Can't decide provider for email address '#{username}'"
|
|
190
|
-
return nil
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
provider.host
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def helpers
|
|
197
|
-
Setup::Helpers.new
|
|
198
|
-
end
|
|
199
122
|
end
|
|
200
123
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module Imap::Backup
|
|
2
2
|
class Setup; end
|
|
3
3
|
|
|
4
|
-
Setup::Asker
|
|
4
|
+
class Setup::Asker
|
|
5
5
|
EMAIL_MATCHER = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+$/i.freeze
|
|
6
6
|
|
|
7
|
+
attr_reader :highline
|
|
8
|
+
|
|
7
9
|
def initialize(highline)
|
|
8
|
-
|
|
10
|
+
@highline = highline
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
def email(default = "")
|
|
@@ -30,15 +32,6 @@ module Imap::Backup
|
|
|
30
32
|
password
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
def backup_path(default, validator)
|
|
34
|
-
highline.ask("backup directory: ") do |q|
|
|
35
|
-
q.default = default
|
|
36
|
-
q.readline = true
|
|
37
|
-
q.validate = validator
|
|
38
|
-
q.responses[:not_valid] = "Choose a different directory "
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
35
|
def self.email(default = "")
|
|
43
36
|
new(Setup.highline).email(default)
|
|
44
37
|
end
|
|
@@ -46,9 +39,5 @@ module Imap::Backup
|
|
|
46
39
|
def self.password
|
|
47
40
|
new(Setup.highline).password
|
|
48
41
|
end
|
|
49
|
-
|
|
50
|
-
def self.backup_path(default, validator)
|
|
51
|
-
new(Setup.highline).backup_path(default, validator)
|
|
52
|
-
end
|
|
53
42
|
end
|
|
54
43
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class Setup; end
|
|
3
|
+
|
|
4
|
+
class Setup::BackupPath
|
|
5
|
+
attr_reader :account
|
|
6
|
+
attr_reader :config
|
|
7
|
+
|
|
8
|
+
def initialize(account:, config:)
|
|
9
|
+
@account = account
|
|
10
|
+
@config = config
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
account.local_path = highline.ask("backup directory: ") do |q|
|
|
15
|
+
q.default = account.local_path
|
|
16
|
+
q.readline = true
|
|
17
|
+
q.validate = ->(path) { path_modification_validator(path) }
|
|
18
|
+
q.responses[:not_valid] = "Choose a different directory "
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def highline
|
|
25
|
+
Setup.highline
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def path_modification_validator(path)
|
|
29
|
+
same = config.accounts.find do |a|
|
|
30
|
+
a.username != account.username && a.local_path == path
|
|
31
|
+
end
|
|
32
|
+
if same
|
|
33
|
+
Kernel.puts "The path '#{path}' is used to backup " \
|
|
34
|
+
"the account '#{same.username}'"
|
|
35
|
+
false
|
|
36
|
+
else
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "email/provider"
|
|
2
|
+
|
|
3
|
+
module Imap::Backup
|
|
4
|
+
class Setup; end
|
|
5
|
+
|
|
6
|
+
class Setup::Email
|
|
7
|
+
attr_reader :account
|
|
8
|
+
attr_reader :config
|
|
9
|
+
|
|
10
|
+
def initialize(account:, config:)
|
|
11
|
+
@account = account
|
|
12
|
+
@config = config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
username = Setup::Asker.email(account.username)
|
|
17
|
+
other_accounts = config.accounts.reject { |a| a == account }
|
|
18
|
+
others = other_accounts.map(&:username)
|
|
19
|
+
if others.include?(username)
|
|
20
|
+
Kernel.puts(
|
|
21
|
+
"There is already an account set up with that email address"
|
|
22
|
+
)
|
|
23
|
+
else
|
|
24
|
+
account.username = username
|
|
25
|
+
if account.server.nil? || (account.server == "")
|
|
26
|
+
default = default_server(username)
|
|
27
|
+
account.server = default if default
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def default_server(username)
|
|
35
|
+
provider = Email::Provider.for_address(username)
|
|
36
|
+
|
|
37
|
+
if provider.is_a?(Email::Provider::Unknown)
|
|
38
|
+
Kernel.puts "Can't decide provider for email address '#{username}'"
|
|
39
|
+
return nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
provider.host
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -12,13 +12,13 @@ module Imap::Backup
|
|
|
12
12
|
|
|
13
13
|
def run
|
|
14
14
|
if connection.nil?
|
|
15
|
-
|
|
15
|
+
Logger.logger.warn "Connection failed"
|
|
16
16
|
highline.ask "Press a key "
|
|
17
17
|
return
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
if imap_folders.nil?
|
|
21
|
-
|
|
21
|
+
Logger.logger.warn "Unable to get folder list"
|
|
22
22
|
highline.ask "Press a key "
|
|
23
23
|
return
|
|
24
24
|
end
|
|
@@ -90,7 +90,7 @@ module Imap::Backup
|
|
|
90
90
|
|
|
91
91
|
def toggle_selection(folder_name)
|
|
92
92
|
if selected?(folder_name)
|
|
93
|
-
new_list = account.folders.
|
|
93
|
+
new_list = account.folders.reject { |f| f[:name] == folder_name }
|
|
94
94
|
account.folders = new_list
|
|
95
95
|
else
|
|
96
96
|
existing = account.folders || []
|
data/lib/imap/backup/setup.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "highline"
|
|
2
2
|
|
|
3
|
+
require "email/provider"
|
|
3
4
|
require "imap/backup/account"
|
|
4
5
|
require "imap/backup/setup/helpers"
|
|
5
6
|
|
|
@@ -36,7 +37,7 @@ module Imap::Backup
|
|
|
36
37
|
config.save
|
|
37
38
|
throw :done
|
|
38
39
|
end
|
|
39
|
-
menu.choice("exit without saving changes")
|
|
40
|
+
menu.choice("exit without saving changes") { throw :done }
|
|
40
41
|
else
|
|
41
42
|
menu.choice("quit") { throw :done }
|
|
42
43
|
end
|
|
@@ -67,7 +68,7 @@ module Imap::Backup
|
|
|
67
68
|
new_setting = !config.debug?
|
|
68
69
|
menu.choice(menu_item) do
|
|
69
70
|
config.debug = new_setting
|
|
70
|
-
|
|
71
|
+
Logger.setup_logging(config)
|
|
71
72
|
end
|
|
72
73
|
end
|
|
73
74
|
|
|
@@ -76,13 +77,13 @@ module Imap::Backup
|
|
|
76
77
|
end
|
|
77
78
|
|
|
78
79
|
def default_account_config(username)
|
|
79
|
-
|
|
80
|
+
Imap::Backup::Account.new(
|
|
80
81
|
username: username,
|
|
81
82
|
password: "",
|
|
82
83
|
local_path: File.join(config.path, username.tr("@", "_")),
|
|
83
84
|
folders: []
|
|
84
85
|
).tap do |a|
|
|
85
|
-
server = Email::Provider.for_address(username)
|
|
86
|
+
server = ::Email::Provider.for_address(username)
|
|
86
87
|
a.server = server.host if server.host
|
|
87
88
|
end
|
|
88
89
|
end
|
|
@@ -21,28 +21,51 @@ module Imap::Backup
|
|
|
21
21
|
local_folder_ok = local_folder.set_up
|
|
22
22
|
return false if !local_folder_ok
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
skip_for_msf = check_msf
|
|
25
|
+
return false if skip_for_msf
|
|
26
|
+
|
|
27
|
+
skip_for_local_folder = check_local_folder
|
|
28
|
+
return false if skip_for_local_folder
|
|
29
|
+
|
|
30
|
+
copy_messages
|
|
31
|
+
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def check_local_folder
|
|
38
|
+
return false if !local_folder.exists?
|
|
39
|
+
|
|
40
|
+
if force
|
|
41
|
+
Kernel.puts "Overwriting '#{local_folder.path}' as --force option was supplied"
|
|
42
|
+
return false
|
|
32
43
|
end
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
Kernel.puts "Skipping export of '#{serializer.folder}' as '#{local_folder.path}' exists"
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def check_msf
|
|
50
|
+
return false if !local_folder.msf_exists?
|
|
51
|
+
|
|
52
|
+
if force
|
|
53
|
+
Kernel.puts "Deleting '#{local_folder.msf_path}' as --force option was supplied"
|
|
54
|
+
File.unlink local_folder.msf_path
|
|
55
|
+
return false
|
|
41
56
|
end
|
|
42
57
|
|
|
58
|
+
Kernel.puts(
|
|
59
|
+
"Skipping export of '#{serializer.folder}' " \
|
|
60
|
+
"as '#{local_folder.msf_path}' exists"
|
|
61
|
+
)
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def copy_messages
|
|
43
66
|
File.open(local_folder.full_path, "w") do |f|
|
|
44
67
|
enumerator = Serializer::MboxEnumerator.new(serializer.mbox_pathname)
|
|
45
|
-
enumerator.each
|
|
68
|
+
enumerator.each do |raw|
|
|
46
69
|
clean = Email::Mboxrd::Message.clean_serialized(raw)
|
|
47
70
|
timestamp = Time.now.strftime("%a %b %d %H:%M:%S %Y")
|
|
48
71
|
thunderbird_fom_line = "From - #{timestamp}"
|
|
@@ -50,12 +73,8 @@ module Imap::Backup
|
|
|
50
73
|
f.write output
|
|
51
74
|
end
|
|
52
75
|
end
|
|
53
|
-
|
|
54
|
-
true
|
|
55
76
|
end
|
|
56
77
|
|
|
57
|
-
private
|
|
58
|
-
|
|
59
78
|
def local_folder
|
|
60
79
|
@local_folder ||= begin
|
|
61
80
|
top_level_folders = [EXPORT_PREFIX, email]
|
data/lib/imap/backup/uploader.rb
CHANGED
|
@@ -9,27 +9,65 @@ module Imap::Backup
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def run
|
|
12
|
-
|
|
12
|
+
if folder.uids.any?
|
|
13
|
+
rename_serialized_folder
|
|
14
|
+
else
|
|
15
|
+
folder.create
|
|
16
|
+
serializer.force_uid_validity(folder.uid_validity)
|
|
17
|
+
end
|
|
18
|
+
|
|
13
19
|
return if count.zero?
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
Logger.logger.debug "[#{folder.name}] #{count} to restore"
|
|
16
22
|
serializer.each_message(missing_uids).with_index do |(uid, message), i|
|
|
17
|
-
|
|
23
|
+
upload_message uid, message, i + 1
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def upload_message(uid, message, index)
|
|
30
|
+
return if message.nil?
|
|
18
31
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
log_prefix = "[#{folder.name}] uid: #{uid} (#{index}/#{count}) -"
|
|
33
|
+
Logger.logger.debug(
|
|
34
|
+
"#{log_prefix} #{message.supplied_body.size} bytes"
|
|
35
|
+
)
|
|
23
36
|
|
|
37
|
+
begin
|
|
24
38
|
new_uid = folder.append(message)
|
|
25
39
|
serializer.update_uid(uid, new_uid)
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
Logger.logger.warn "#{log_prefix} append error: #{e}"
|
|
26
42
|
end
|
|
27
43
|
end
|
|
28
44
|
|
|
29
|
-
|
|
45
|
+
def count
|
|
46
|
+
@count ||= missing_uids.count
|
|
47
|
+
end
|
|
30
48
|
|
|
31
49
|
def missing_uids
|
|
32
50
|
serializer.uids - folder.uids
|
|
33
51
|
end
|
|
52
|
+
|
|
53
|
+
def rename_serialized_folder
|
|
54
|
+
Logger.logger.debug(
|
|
55
|
+
"There's already a '#{folder.name}' folder with emails"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Rename the local folder to a unique name
|
|
59
|
+
new_name = serializer.apply_uid_validity(folder.uid_validity)
|
|
60
|
+
|
|
61
|
+
return if !new_name
|
|
62
|
+
|
|
63
|
+
# Restore the renamed folder
|
|
64
|
+
Logger.logger.debug(
|
|
65
|
+
"Backup '#{serializer.folder}' renamed and restored to '#{new_name}'"
|
|
66
|
+
)
|
|
67
|
+
@folder = Account::Folder.new(folder.connection, new_name)
|
|
68
|
+
folder.create
|
|
69
|
+
@serializer = Serializer.new(serializer.path, new_name)
|
|
70
|
+
serializer.force_uid_validity(@folder.uid_validity)
|
|
71
|
+
end
|
|
34
72
|
end
|
|
35
73
|
end
|
data/lib/imap/backup/utils.rb
CHANGED
data/lib/imap/backup/version.rb
CHANGED
data/lib/imap/backup.rb
CHANGED
|
@@ -14,7 +14,6 @@ require "imap/backup/setup/asker"
|
|
|
14
14
|
require "imap/backup/setup/connection_tester"
|
|
15
15
|
require "imap/backup/setup/folder_chooser"
|
|
16
16
|
require "imap/backup/version"
|
|
17
|
-
require "email/provider"
|
|
18
17
|
|
|
19
18
|
module Imap::Backup
|
|
20
19
|
class ConfigurationNotFound < StandardError; end
|