imap-backup 5.2.0 → 6.0.1
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/README.md +9 -2
- data/docs/development.md +10 -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 +17 -105
- data/lib/imap/backup/account/folder.rb +9 -6
- data/lib/imap/backup/account.rb +36 -16
- data/lib/imap/backup/cli/backup.rb +1 -3
- data/lib/imap/backup/cli/folders.rb +3 -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 +5 -11
- 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 +6 -8
- data/lib/imap/backup/cli.rb +24 -3
- data/lib/imap/backup/configuration.rb +9 -21
- data/lib/imap/backup/downloader.rb +56 -34
- 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/directory.rb +37 -0
- data/lib/imap/backup/serializer/imap.rb +144 -0
- data/lib/imap/backup/serializer/mbox.rb +33 -88
- data/lib/imap/backup/serializer/mbox_enumerator.rb +2 -0
- data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
- data/lib/imap/backup/serializer/unused_name_finder.rb +25 -0
- data/lib/imap/backup/serializer.rb +160 -3
- data/lib/imap/backup/setup/account/header.rb +75 -0
- data/lib/imap/backup/setup/account.rb +41 -95
- 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 +2 -2
- data/lib/imap/backup/setup.rb +5 -4
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +41 -22
- data/lib/imap/backup/uploader.rb +46 -8
- data/lib/imap/backup/utils.rb +1 -1
- data/lib/imap/backup/version.rb +3 -3
- data/lib/imap/backup.rb +0 -2
- metadata +31 -105
- data/lib/imap/backup/serializer/mbox_store.rb +0 -217
- data/spec/features/backup_spec.rb +0 -108
- 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 -77
- 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 -405
- data/spec/unit/imap/backup/account/folder_spec.rb +0 -251
- data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -47
- data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
- data/spec/unit/imap/backup/cli/local_spec.rb +0 -81
- data/spec/unit/imap/backup/cli/utils_spec.rb +0 -62
- 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 -44
- 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/serializer/mbox_enumerator_spec.rb +0 -45
- data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -222
- data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +0 -329
- data/spec/unit/imap/backup/setup/account_spec.rb +0 -366
- 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_spec.rb +0 -301
- data/spec/unit/imap/backup/uploader_spec.rb +0 -54
- data/spec/unit/imap/backup/utils_spec.rb +0 -92
|
@@ -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
|
|
@@ -26,6 +34,7 @@ module Imap::Backup
|
|
|
26
34
|
modify_password menu
|
|
27
35
|
modify_backup_path menu
|
|
28
36
|
choose_folders menu
|
|
37
|
+
modify_multi_fetch_size menu
|
|
29
38
|
modify_server menu
|
|
30
39
|
modify_connection_options menu
|
|
31
40
|
test_connection menu
|
|
@@ -36,47 +45,12 @@ module Imap::Backup
|
|
|
36
45
|
end
|
|
37
46
|
|
|
38
47
|
def header(menu)
|
|
39
|
-
|
|
40
|
-
connection_options =
|
|
41
|
-
if account.connection_options
|
|
42
|
-
escaped =
|
|
43
|
-
JSON.generate(account.connection_options).
|
|
44
|
-
gsub('"', '\"')
|
|
45
|
-
"\n connection options #{escaped}"
|
|
46
|
-
end
|
|
47
|
-
menu.header = <<~HEADER.chomp
|
|
48
|
-
#{helpers.title_prefix} Account#{modified}
|
|
49
|
-
|
|
50
|
-
email #{account.username}
|
|
51
|
-
password #{masked_password}
|
|
52
|
-
path #{account.local_path}
|
|
53
|
-
folders #{folders.map { |f| f[:name] }.join(', ')}
|
|
54
|
-
server #{account.server}#{connection_options}
|
|
55
|
-
|
|
56
|
-
Choose an action
|
|
57
|
-
HEADER
|
|
48
|
+
Setup::Account::Header.new(menu: menu, account: account).run
|
|
58
49
|
end
|
|
59
50
|
|
|
60
51
|
def modify_email(menu)
|
|
61
52
|
menu.choice("modify email") do
|
|
62
|
-
|
|
63
|
-
Kernel.puts "username: #{username}"
|
|
64
|
-
other_accounts = config.accounts.reject { |a| a == account }
|
|
65
|
-
others = other_accounts.map { |a| a.username }
|
|
66
|
-
Kernel.puts "others: #{others.inspect}"
|
|
67
|
-
if others.include?(username)
|
|
68
|
-
Kernel.puts(
|
|
69
|
-
"There is already an account set up with that email address"
|
|
70
|
-
)
|
|
71
|
-
else
|
|
72
|
-
account.username = username
|
|
73
|
-
# rubocop:disable Style/IfUnlessModifier
|
|
74
|
-
default = default_server(username)
|
|
75
|
-
if default && (account.server.nil? || (account.server == ""))
|
|
76
|
-
account.server = default
|
|
77
|
-
end
|
|
78
|
-
# rubocop:enable Style/IfUnlessModifier
|
|
79
|
-
end
|
|
53
|
+
Setup::Email.new(account: account, config: config).run
|
|
80
54
|
end
|
|
81
55
|
end
|
|
82
56
|
|
|
@@ -88,45 +62,44 @@ module Imap::Backup
|
|
|
88
62
|
end
|
|
89
63
|
end
|
|
90
64
|
|
|
91
|
-
def
|
|
92
|
-
menu.choice("modify
|
|
93
|
-
|
|
94
|
-
account.server = server if !server.nil?
|
|
65
|
+
def modify_backup_path(menu)
|
|
66
|
+
menu.choice("modify backup path") do
|
|
67
|
+
Setup::BackupPath.new(account: account, config: config).run
|
|
95
68
|
end
|
|
96
69
|
end
|
|
97
70
|
|
|
98
|
-
def
|
|
99
|
-
menu.choice("
|
|
100
|
-
|
|
101
|
-
account.connection_options = connection_options if !connection_options.nil?
|
|
71
|
+
def choose_folders(menu)
|
|
72
|
+
menu.choice("choose backup folders") do
|
|
73
|
+
Setup::FolderChooser.new(account).run
|
|
102
74
|
end
|
|
103
75
|
end
|
|
104
76
|
|
|
105
|
-
def
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Kernel.puts "The path '#{path}' is used to backup " \
|
|
111
|
-
"the account '#{same.username}'"
|
|
112
|
-
false
|
|
113
|
-
else
|
|
114
|
-
true
|
|
77
|
+
def modify_multi_fetch_size(menu)
|
|
78
|
+
menu.choice("modify multi-fetch size (number of emails to fetch at a time)") do
|
|
79
|
+
size = highline.ask("size: ")
|
|
80
|
+
int = size.to_i
|
|
81
|
+
account.multi_fetch_size = int if int.positive?
|
|
115
82
|
end
|
|
116
83
|
end
|
|
117
84
|
|
|
118
|
-
def
|
|
119
|
-
menu.choice("modify
|
|
120
|
-
|
|
121
|
-
account.
|
|
122
|
-
account.local_path, ->(path) { path_modification_validator(path) }
|
|
123
|
-
)
|
|
85
|
+
def modify_server(menu)
|
|
86
|
+
menu.choice("modify server") do
|
|
87
|
+
server = highline.ask("server: ")
|
|
88
|
+
account.server = server if !server.nil?
|
|
124
89
|
end
|
|
125
90
|
end
|
|
126
91
|
|
|
127
|
-
def
|
|
128
|
-
menu.choice("
|
|
129
|
-
|
|
92
|
+
def modify_connection_options(menu)
|
|
93
|
+
menu.choice("modify connection options") do
|
|
94
|
+
connection_options = highline.ask("connections options (as JSON): ")
|
|
95
|
+
if !connection_options.nil?
|
|
96
|
+
begin
|
|
97
|
+
account.connection_options = connection_options
|
|
98
|
+
rescue JSON::ParserError
|
|
99
|
+
Kernel.puts "Malformed JSON, please try again"
|
|
100
|
+
highline.ask "Press a key "
|
|
101
|
+
end
|
|
102
|
+
end
|
|
130
103
|
end
|
|
131
104
|
end
|
|
132
105
|
|
|
@@ -141,37 +114,10 @@ module Imap::Backup
|
|
|
141
114
|
def delete_account(menu)
|
|
142
115
|
menu.choice("delete") do
|
|
143
116
|
if highline.agree("Are you sure? (y/n) ")
|
|
144
|
-
account.mark_for_deletion
|
|
117
|
+
account.mark_for_deletion
|
|
145
118
|
throw :done
|
|
146
119
|
end
|
|
147
120
|
end
|
|
148
121
|
end
|
|
149
|
-
|
|
150
|
-
def folders
|
|
151
|
-
account.folders || []
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def masked_password
|
|
155
|
-
if (account.password == "") || account.password.nil?
|
|
156
|
-
"(unset)"
|
|
157
|
-
else
|
|
158
|
-
account.password.gsub(/./, "x")
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def default_server(username)
|
|
163
|
-
provider = Email::Provider.for_address(username)
|
|
164
|
-
|
|
165
|
-
if provider.is_a?(Email::Provider::Unknown)
|
|
166
|
-
Kernel.puts "Can't decide provider for email address '#{username}'"
|
|
167
|
-
return nil
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
provider.host
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def helpers
|
|
174
|
-
Setup::Helpers.new
|
|
175
|
-
end
|
|
176
122
|
end
|
|
177
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
|
|
@@ -19,30 +19,53 @@ module Imap::Backup
|
|
|
19
19
|
|
|
20
20
|
def run
|
|
21
21
|
local_folder_ok = local_folder.set_up
|
|
22
|
-
return if !local_folder_ok
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
return false if !local_folder_ok
|
|
23
|
+
|
|
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
|
@@ -8,14 +8,12 @@ require "imap/backup/downloader"
|
|
|
8
8
|
require "imap/backup/logger"
|
|
9
9
|
require "imap/backup/uploader"
|
|
10
10
|
require "imap/backup/serializer"
|
|
11
|
-
require "imap/backup/serializer/mbox"
|
|
12
11
|
require "imap/backup/setup"
|
|
13
12
|
require "imap/backup/setup/account"
|
|
14
13
|
require "imap/backup/setup/asker"
|
|
15
14
|
require "imap/backup/setup/connection_tester"
|
|
16
15
|
require "imap/backup/setup/folder_chooser"
|
|
17
16
|
require "imap/backup/version"
|
|
18
|
-
require "email/provider"
|
|
19
17
|
|
|
20
18
|
module Imap::Backup
|
|
21
19
|
class ConfigurationNotFound < StandardError; end
|