imap-backup 5.2.0 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,37 @@
|
|
1
|
+
require "os"
|
2
|
+
|
3
|
+
module Imap::Backup
|
4
|
+
class Serializer; end
|
5
|
+
|
6
|
+
class Serializer::Directory
|
7
|
+
DIRECTORY_PERMISSIONS = 0o700
|
8
|
+
|
9
|
+
attr_reader :relative
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
def initialize(path, relative)
|
13
|
+
@path = path
|
14
|
+
@relative = relative
|
15
|
+
end
|
16
|
+
|
17
|
+
def ensure_exists
|
18
|
+
if !File.directory?(full_path)
|
19
|
+
Utils.make_folder(
|
20
|
+
path, relative, DIRECTORY_PERMISSIONS
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
return if OS.windows?
|
25
|
+
return if Utils.mode(full_path) == DIRECTORY_PERMISSIONS
|
26
|
+
|
27
|
+
FileUtils.chmod DIRECTORY_PERMISSIONS, full_path
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def full_path
|
33
|
+
containing_directory = File.join(path, relative)
|
34
|
+
File.expand_path(containing_directory)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Imap::Backup
|
4
|
+
class Serializer::Imap
|
5
|
+
CURRENT_VERSION = 2
|
6
|
+
|
7
|
+
attr_reader :folder_path
|
8
|
+
attr_reader :loaded
|
9
|
+
|
10
|
+
def initialize(folder_path)
|
11
|
+
@folder_path = folder_path
|
12
|
+
@loaded = false
|
13
|
+
@uid_validity = nil
|
14
|
+
@uids = nil
|
15
|
+
@version = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid?
|
19
|
+
return false if !exist?
|
20
|
+
return false if version != CURRENT_VERSION
|
21
|
+
return false if !uid_validity
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def append(uid)
|
27
|
+
uids << uid
|
28
|
+
save
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete
|
32
|
+
return if !exist?
|
33
|
+
|
34
|
+
File.unlink(pathname)
|
35
|
+
end
|
36
|
+
|
37
|
+
def include?(uid)
|
38
|
+
uids.include?(uid)
|
39
|
+
end
|
40
|
+
|
41
|
+
def index(uid)
|
42
|
+
uids.find_index(uid)
|
43
|
+
end
|
44
|
+
|
45
|
+
def rename(new_path)
|
46
|
+
if exist?
|
47
|
+
old_pathname = pathname
|
48
|
+
@folder_path = new_path
|
49
|
+
File.rename(old_pathname, pathname)
|
50
|
+
else
|
51
|
+
@folder_path = new_path
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def uid_validity
|
56
|
+
ensure_loaded
|
57
|
+
@uid_validity
|
58
|
+
end
|
59
|
+
|
60
|
+
def uid_validity=(value)
|
61
|
+
ensure_loaded
|
62
|
+
@uid_validity = value
|
63
|
+
@uids ||= []
|
64
|
+
save
|
65
|
+
end
|
66
|
+
|
67
|
+
def uids
|
68
|
+
ensure_loaded
|
69
|
+
@uids || []
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_uid(old, new)
|
73
|
+
index = uids.find_index(old.to_i)
|
74
|
+
return if index.nil?
|
75
|
+
|
76
|
+
uids[index] = new.to_i
|
77
|
+
save
|
78
|
+
end
|
79
|
+
|
80
|
+
def version
|
81
|
+
ensure_loaded
|
82
|
+
@version
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def pathname
|
88
|
+
"#{folder_path}.imap"
|
89
|
+
end
|
90
|
+
|
91
|
+
def exist?
|
92
|
+
File.exist?(pathname)
|
93
|
+
end
|
94
|
+
|
95
|
+
def ensure_loaded
|
96
|
+
return if loaded
|
97
|
+
|
98
|
+
data = load
|
99
|
+
if data
|
100
|
+
@uids = data[:uids].map(&:to_i)
|
101
|
+
@uid_validity = data[:uid_validity]
|
102
|
+
@version = data[:version]
|
103
|
+
else
|
104
|
+
@uids = []
|
105
|
+
@uid_validity = nil
|
106
|
+
@version = CURRENT_VERSION
|
107
|
+
end
|
108
|
+
@loaded = true
|
109
|
+
end
|
110
|
+
|
111
|
+
def load
|
112
|
+
return nil if !exist?
|
113
|
+
|
114
|
+
data = nil
|
115
|
+
begin
|
116
|
+
content = File.read(pathname)
|
117
|
+
data = JSON.parse(content, symbolize_names: true)
|
118
|
+
rescue JSON::ParserError
|
119
|
+
return nil
|
120
|
+
end
|
121
|
+
|
122
|
+
return nil if !data.key?(:version)
|
123
|
+
return nil if !data.key?(:uid_validity)
|
124
|
+
return nil if !data.key?(:uids)
|
125
|
+
return nil if !data[:uids].is_a?(Array)
|
126
|
+
|
127
|
+
data
|
128
|
+
end
|
129
|
+
|
130
|
+
def save
|
131
|
+
ensure_loaded
|
132
|
+
|
133
|
+
raise "Cannot save metadata without a uid_validity" if !uid_validity
|
134
|
+
|
135
|
+
data = {
|
136
|
+
version: @version,
|
137
|
+
uid_validity: @uid_validity,
|
138
|
+
uids: @uids
|
139
|
+
}
|
140
|
+
content = data.to_json
|
141
|
+
File.open(pathname, "w") { |f| f.write content }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -1,116 +1,61 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
|
3
|
-
require "imap/backup/serializer/mbox_store"
|
4
|
-
|
5
1
|
module Imap::Backup
|
6
2
|
class Serializer::Mbox
|
7
|
-
|
8
|
-
def_delegators :store, :mbox_pathname
|
9
|
-
|
10
|
-
attr_reader :path
|
11
|
-
attr_reader :folder
|
12
|
-
|
13
|
-
def initialize(path, folder)
|
14
|
-
@path = path
|
15
|
-
@folder = folder
|
16
|
-
end
|
17
|
-
|
18
|
-
def apply_uid_validity(value)
|
19
|
-
case
|
20
|
-
when store.uid_validity.nil?
|
21
|
-
store.uid_validity = value
|
22
|
-
nil
|
23
|
-
when store.uid_validity == value
|
24
|
-
# NOOP
|
25
|
-
nil
|
26
|
-
else
|
27
|
-
apply_new_uid_validity value
|
28
|
-
end
|
29
|
-
end
|
3
|
+
attr_reader :folder_path
|
30
4
|
|
31
|
-
def
|
32
|
-
|
5
|
+
def initialize(folder_path)
|
6
|
+
@folder_path = folder_path
|
33
7
|
end
|
34
8
|
|
35
|
-
def
|
36
|
-
|
9
|
+
def valid?
|
10
|
+
exist?
|
37
11
|
end
|
38
12
|
|
39
|
-
def
|
40
|
-
|
13
|
+
def append(message)
|
14
|
+
File.open(pathname, "ab") do |file|
|
15
|
+
file.write message
|
16
|
+
end
|
41
17
|
end
|
42
18
|
|
43
|
-
def
|
44
|
-
|
45
|
-
end
|
19
|
+
def delete
|
20
|
+
return if !exist?
|
46
21
|
|
47
|
-
|
48
|
-
store.add(uid, message)
|
22
|
+
File.unlink(pathname)
|
49
23
|
end
|
50
24
|
|
51
|
-
def
|
52
|
-
|
53
|
-
store.rename new_name
|
54
|
-
end
|
25
|
+
def length
|
26
|
+
return nil if !exist?
|
55
27
|
|
56
|
-
|
57
|
-
store.update_uid old, new
|
28
|
+
File.stat(pathname).size
|
58
29
|
end
|
59
30
|
|
60
|
-
|
61
|
-
|
62
|
-
def store
|
63
|
-
@store ||=
|
64
|
-
begin
|
65
|
-
create_containing_directory
|
66
|
-
Serializer::MboxStore.new(path, folder)
|
67
|
-
end
|
31
|
+
def pathname
|
32
|
+
"#{folder_path}.mbox"
|
68
33
|
end
|
69
34
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
break if !test_store.exist?
|
78
|
-
|
79
|
-
digit += 1
|
35
|
+
def rename(new_path)
|
36
|
+
if exist?
|
37
|
+
old_pathname = pathname
|
38
|
+
@folder_path = new_path
|
39
|
+
File.rename(old_pathname, pathname)
|
40
|
+
else
|
41
|
+
@folder_path = new_path
|
80
42
|
end
|
81
|
-
rename_store new_name, value
|
82
|
-
end
|
83
|
-
|
84
|
-
def rename_store(new_name, value)
|
85
|
-
store.rename new_name
|
86
|
-
@store = nil
|
87
|
-
store.uid_validity = value
|
88
|
-
new_name
|
89
43
|
end
|
90
44
|
|
91
|
-
def
|
92
|
-
File.
|
93
|
-
|
94
|
-
|
95
|
-
def containing_directory
|
96
|
-
File.join(path, relative_path)
|
45
|
+
def rewind(length)
|
46
|
+
File.open(pathname, File::RDWR | File::CREAT, 0o644) do |f|
|
47
|
+
f.truncate(length)
|
48
|
+
end
|
97
49
|
end
|
98
50
|
|
99
|
-
def
|
100
|
-
File.
|
51
|
+
def touch
|
52
|
+
File.open(pathname, "a") {}
|
101
53
|
end
|
102
54
|
|
103
|
-
|
104
|
-
if !File.directory?(full_path)
|
105
|
-
Utils.make_folder(
|
106
|
-
path, relative_path, Serializer::DIRECTORY_PERMISSIONS
|
107
|
-
)
|
108
|
-
end
|
55
|
+
private
|
109
56
|
|
110
|
-
|
111
|
-
|
112
|
-
FileUtils.chmod Serializer::DIRECTORY_PERMISSIONS, full_path
|
113
|
-
end
|
57
|
+
def exist?
|
58
|
+
File.exist?(pathname)
|
114
59
|
end
|
115
60
|
end
|
116
61
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "email/mboxrd/message"
|
2
|
+
require "imap/backup/serializer/mbox_enumerator"
|
3
|
+
|
4
|
+
module Imap::Backup
|
5
|
+
class Serializer::MessageEnumerator
|
6
|
+
attr_reader :imap
|
7
|
+
attr_reader :mbox
|
8
|
+
|
9
|
+
def initialize(imap:, mbox:)
|
10
|
+
@imap = imap
|
11
|
+
@mbox = mbox
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(uids:)
|
15
|
+
indexes = uids.each.with_object({}) do |uid_maybe_string, acc|
|
16
|
+
uid = uid_maybe_string.to_i
|
17
|
+
index = imap.index(uid)
|
18
|
+
acc[index] = uid if index
|
19
|
+
end
|
20
|
+
enumerator = Serializer::MboxEnumerator.new(mbox.pathname)
|
21
|
+
enumerator.each.with_index do |raw, i|
|
22
|
+
uid = indexes[i]
|
23
|
+
next if !uid
|
24
|
+
|
25
|
+
yield uid, Email::Mboxrd::Message.from_serialized(raw)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
class Serializer::UnusedNameFinder
|
3
|
+
attr_reader :serializer
|
4
|
+
|
5
|
+
def initialize(serializer:)
|
6
|
+
@serializer = serializer
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
digit = 0
|
11
|
+
folder = nil
|
12
|
+
|
13
|
+
loop do
|
14
|
+
extra = digit.zero? ? "" : "-#{digit}"
|
15
|
+
folder = "#{serializer.folder}-#{serializer.uid_validity}#{extra}"
|
16
|
+
test = Serializer.new(serializer.path, folder)
|
17
|
+
break if !test.validate!
|
18
|
+
|
19
|
+
digit += 1
|
20
|
+
end
|
21
|
+
|
22
|
+
folder
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,163 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
require "email/mboxrd/message"
|
4
|
+
require "imap/backup/serializer/appender"
|
5
|
+
require "imap/backup/serializer/imap"
|
6
|
+
require "imap/backup/serializer/mbox"
|
7
|
+
require "imap/backup/serializer/mbox_enumerator"
|
8
|
+
require "imap/backup/serializer/message_enumerator"
|
9
|
+
require "imap/backup/serializer/unused_name_finder"
|
10
|
+
|
1
11
|
module Imap::Backup
|
2
|
-
|
3
|
-
|
4
|
-
|
12
|
+
class Serializer
|
13
|
+
def self.folder_path_for(path:, folder:)
|
14
|
+
relative = File.join(path, folder)
|
15
|
+
File.expand_path(relative)
|
16
|
+
end
|
17
|
+
|
18
|
+
extend Forwardable
|
19
|
+
|
20
|
+
def_delegator :mbox, :pathname, :mbox_pathname
|
21
|
+
def_delegators :imap, :uid_validity, :uids, :update_uid
|
22
|
+
|
23
|
+
attr_reader :folder
|
24
|
+
attr_reader :path
|
25
|
+
|
26
|
+
def initialize(path, folder)
|
27
|
+
@path = path
|
28
|
+
@folder = folder
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns true if there are existing, valid files
|
32
|
+
# false otherwise (in which case any existing files are deleted)
|
33
|
+
def validate!
|
34
|
+
return true if imap.valid? && mbox.valid?
|
35
|
+
|
36
|
+
imap.delete
|
37
|
+
@imap = nil
|
38
|
+
mbox.delete
|
39
|
+
@mbox = nil
|
40
|
+
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply_uid_validity(value)
|
45
|
+
validate!
|
46
|
+
|
47
|
+
case
|
48
|
+
when uid_validity.nil?
|
49
|
+
internal_force_uid_validity(value)
|
50
|
+
nil
|
51
|
+
when uid_validity == value
|
52
|
+
# NOOP
|
53
|
+
nil
|
54
|
+
else
|
55
|
+
apply_new_uid_validity value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def force_uid_validity(value)
|
60
|
+
validate!
|
61
|
+
|
62
|
+
internal_force_uid_validity(value)
|
63
|
+
end
|
64
|
+
|
65
|
+
def append(uid, message)
|
66
|
+
validate!
|
67
|
+
|
68
|
+
appender = Serializer::Appender.new(folder: folder, imap: imap, mbox: mbox)
|
69
|
+
appender.run(uid: uid, message: message)
|
70
|
+
end
|
71
|
+
|
72
|
+
def load(uid_maybe_string)
|
73
|
+
validate!
|
74
|
+
|
75
|
+
uid = uid_maybe_string.to_i
|
76
|
+
message_index = imap.index(uid)
|
77
|
+
return nil if message_index.nil?
|
78
|
+
|
79
|
+
internal_load_nth(message_index)
|
80
|
+
end
|
81
|
+
|
82
|
+
def load_nth(index)
|
83
|
+
validate!
|
84
|
+
|
85
|
+
internal_load_nth(index)
|
86
|
+
end
|
87
|
+
|
88
|
+
def each_message(required_uids, &block)
|
89
|
+
validate!
|
90
|
+
|
91
|
+
return enum_for(:each_message, required_uids) if !block
|
92
|
+
|
93
|
+
enumerator = Serializer::MessageEnumerator.new(imap: imap, mbox: mbox)
|
94
|
+
enumerator.run(uids: required_uids, &block)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def rename(new_name)
|
100
|
+
destination = self.class.folder_path_for(path: path, folder: new_name)
|
101
|
+
ensure_containing_directory(new_name)
|
102
|
+
mbox.rename destination
|
103
|
+
imap.rename destination
|
104
|
+
end
|
105
|
+
|
106
|
+
def internal_force_uid_validity(value)
|
107
|
+
imap.uid_validity = value
|
108
|
+
mbox.touch
|
109
|
+
end
|
110
|
+
|
111
|
+
def internal_load_nth(index)
|
112
|
+
enumerator = Serializer::MboxEnumerator.new(mbox.pathname)
|
113
|
+
enumerator.each.with_index do |raw, i|
|
114
|
+
next if i != index
|
115
|
+
|
116
|
+
return Email::Mboxrd::Message.from_serialized(raw)
|
117
|
+
end
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
def mbox
|
122
|
+
@mbox ||=
|
123
|
+
begin
|
124
|
+
ensure_containing_directory(folder)
|
125
|
+
Serializer::Mbox.new(folder_path)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def imap
|
130
|
+
@imap ||=
|
131
|
+
begin
|
132
|
+
ensure_containing_directory(folder)
|
133
|
+
Serializer::Imap.new(folder_path)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def folder_path
|
138
|
+
self.class.folder_path_for(path: path, folder: folder)
|
139
|
+
end
|
140
|
+
|
141
|
+
def ensure_containing_directory(folder)
|
142
|
+
relative = File.dirname(folder)
|
143
|
+
directory = Serializer::Directory.new(path, relative)
|
144
|
+
directory.ensure_exists
|
145
|
+
end
|
146
|
+
|
147
|
+
def apply_new_uid_validity(value)
|
148
|
+
new_name = rename_existing_folder
|
149
|
+
# Clear memoization so we get empty data
|
150
|
+
@mbox = nil
|
151
|
+
@imap = nil
|
152
|
+
internal_force_uid_validity(value)
|
153
|
+
|
154
|
+
new_name
|
155
|
+
end
|
156
|
+
|
157
|
+
def rename_existing_folder
|
158
|
+
new_name = Serializer::UnusedNameFinder.new(serializer: self).run
|
159
|
+
rename new_name
|
160
|
+
new_name
|
161
|
+
end
|
5
162
|
end
|
6
163
|
end
|
@@ -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
|