imap-backup 14.4.4 → 14.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +67 -137
- data/docs/documentation.md +19 -0
- data/lib/imap/backup/account/backup.rb +2 -0
- data/lib/imap/backup/account/backup_folders.rb +7 -1
- data/lib/imap/backup/account/client_factory.rb +1 -0
- data/lib/imap/backup/account/folder.rb +26 -0
- data/lib/imap/backup/account/folder_backup.rb +4 -1
- data/lib/imap/backup/account/folder_ensurer.rb +3 -0
- data/lib/imap/backup/account/local_only_folder_deleter.rb +2 -0
- data/lib/imap/backup/account/restore.rb +2 -0
- data/lib/imap/backup/account/serialized_folders.rb +5 -1
- data/lib/imap/backup/account.rb +15 -11
- data/lib/imap/backup/cli/backup.rb +3 -0
- data/lib/imap/backup/cli/folder_enumerator.rb +6 -0
- data/lib/imap/backup/cli/helpers.rb +13 -0
- data/lib/imap/backup/cli/local/check.rb +3 -0
- data/lib/imap/backup/cli/local.rb +13 -0
- data/lib/imap/backup/cli/remote.rb +7 -0
- data/lib/imap/backup/cli/restore.rb +4 -0
- data/lib/imap/backup/cli/setup.rb +3 -0
- data/lib/imap/backup/cli/single/backup.rb +3 -0
- data/lib/imap/backup/cli/single.rb +4 -0
- data/lib/imap/backup/cli/stats.rb +3 -0
- data/lib/imap/backup/cli/transfer.rb +8 -0
- data/lib/imap/backup/cli/utils.rb +6 -0
- data/lib/imap/backup/cli.rb +8 -0
- data/lib/imap/backup/client/apple_mail.rb +2 -0
- data/lib/imap/backup/client/automatic_login_wrapper.rb +9 -1
- data/lib/imap/backup/client/default.rb +15 -4
- data/lib/imap/backup/configuration.rb +13 -0
- data/lib/imap/backup/configuration_not_found.rb +1 -0
- data/lib/imap/backup/downloader.rb +4 -0
- data/lib/imap/backup/email/mboxrd/message.rb +14 -0
- data/lib/imap/backup/email/provider/apple_mail.rb +2 -0
- data/lib/imap/backup/email/provider/base.rb +2 -0
- data/lib/imap/backup/email/provider/fastmail.rb +2 -0
- data/lib/imap/backup/email/provider/gmail.rb +2 -0
- data/lib/imap/backup/email/provider/purelymail.rb +2 -0
- data/lib/imap/backup/email/provider/unknown.rb +2 -6
- data/lib/imap/backup/email/provider.rb +5 -0
- data/lib/imap/backup/file_mode.rb +2 -0
- data/lib/imap/backup/flag_refresher.rb +4 -0
- data/lib/imap/backup/local_only_message_deleter.rb +2 -0
- data/lib/imap/backup/logger.rb +18 -0
- data/lib/imap/backup/migrator.rb +3 -0
- data/lib/imap/backup/mirror/map.rb +21 -0
- data/lib/imap/backup/mirror.rb +8 -0
- data/lib/imap/backup/naming.rb +10 -1
- data/lib/imap/backup/retry_on_error.rb +9 -0
- data/lib/imap/backup/serializer/appender.rb +9 -0
- data/lib/imap/backup/serializer/delayed_metadata_serializer.rb +4 -0
- data/lib/imap/backup/serializer/folder_maker.rb +1 -0
- data/lib/imap/backup/serializer/imap.rb +38 -2
- data/lib/imap/backup/serializer/integrity_checker.rb +1 -0
- data/lib/imap/backup/serializer/mbox.rb +26 -0
- data/lib/imap/backup/serializer/message.rb +13 -0
- data/lib/imap/backup/serializer/message_enumerator.rb +10 -2
- data/lib/imap/backup/serializer/permission_checker.rb +6 -0
- data/lib/imap/backup/serializer/transaction.rb +18 -0
- data/lib/imap/backup/serializer/unused_name_finder.rb +4 -0
- data/lib/imap/backup/serializer/version2_migrator.rb +4 -0
- data/lib/imap/backup/serializer.rb +56 -2
- data/lib/imap/backup/setup/account/header.rb +6 -0
- data/lib/imap/backup/setup/account.rb +6 -0
- data/lib/imap/backup/setup/asker.rb +16 -0
- data/lib/imap/backup/setup/backup_path.rb +6 -0
- data/lib/imap/backup/setup/connection_tester.rb +5 -0
- data/lib/imap/backup/setup/email_changer.rb +6 -0
- data/lib/imap/backup/setup/folder_chooser.rb +4 -0
- data/lib/imap/backup/setup/global_options/download_strategy_chooser.rb +4 -0
- data/lib/imap/backup/setup/global_options.rb +4 -0
- data/lib/imap/backup/setup/helpers.rb +3 -0
- data/lib/imap/backup/setup.rb +5 -0
- data/lib/imap/backup/text/sanitizer.rb +9 -0
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +7 -0
- data/lib/imap/backup/uploader.rb +5 -0
- data/lib/imap/backup/version.rb +6 -1
- metadata +3 -5
- data/docs/api.md +0 -20
- data/docs/development.md +0 -110
- data/docs/migrate-server-keep-address.md +0 -47
@@ -1,15 +1,23 @@
|
|
1
1
|
module Imap; end
|
2
2
|
|
3
3
|
module Imap::Backup
|
4
|
+
# Stores data during a transaction
|
4
5
|
class Serializer::Transaction
|
6
|
+
# @return the transaction's stored data
|
5
7
|
attr_reader :data
|
6
8
|
|
9
|
+
# @param owner [any] the class using the transaction -
|
10
|
+
# this is used when raising errors
|
7
11
|
def initialize(owner:)
|
8
12
|
@data = nil
|
9
13
|
@owner = owner
|
10
14
|
@in_transaction = false
|
11
15
|
end
|
12
16
|
|
17
|
+
# Runs the transaction
|
18
|
+
# @param data [any] the data to maintain during the transaction
|
19
|
+
# @param block [block] the block to wrap with the transaction
|
20
|
+
# @return [void]
|
13
21
|
def begin(data, &block)
|
14
22
|
@data = data
|
15
23
|
@in_transaction = true
|
@@ -17,6 +25,8 @@ module Imap::Backup
|
|
17
25
|
@in_transaction = false
|
18
26
|
end
|
19
27
|
|
28
|
+
# Clears rollback data
|
29
|
+
# @return [void]
|
20
30
|
def clear
|
21
31
|
@data = nil
|
22
32
|
end
|
@@ -25,10 +35,18 @@ module Imap::Backup
|
|
25
35
|
@in_transaction
|
26
36
|
end
|
27
37
|
|
38
|
+
# Throws an exception if there is a current transaction
|
39
|
+
# @param method [Symbol] the method where the check is run
|
40
|
+
# @raise [RuntimeError] if called from inside a transaction
|
41
|
+
# @return [void]
|
28
42
|
def fail_in_transaction!(method, message: "not supported inside trasactions")
|
29
43
|
raise "#{owner.class}##{method} #{message}" if in_transaction?
|
30
44
|
end
|
31
45
|
|
46
|
+
# Throws an exception if there is not a current transaction
|
47
|
+
# @param method [Symbol] the method where the check is run
|
48
|
+
# @raise [RuntimeError] if called from outside a transaction
|
49
|
+
# @return [void]
|
32
50
|
def fail_outside_transaction!(method)
|
33
51
|
raise "#{owner.class}##{method} can only be called inside a transaction" if !in_transaction?
|
34
52
|
end
|
@@ -3,11 +3,15 @@ require "imap/backup/serializer"
|
|
3
3
|
module Imap; end
|
4
4
|
|
5
5
|
module Imap::Backup
|
6
|
+
# Finds a name that can be used to rename a serialized folder
|
6
7
|
class Serializer::UnusedNameFinder
|
8
|
+
# @param serializer [Serializer] a folder serializer
|
7
9
|
def initialize(serializer:)
|
8
10
|
@serializer = serializer
|
9
11
|
end
|
10
12
|
|
13
|
+
# Finds the name
|
14
|
+
# @return [String] the name
|
11
15
|
def run
|
12
16
|
digit = 0
|
13
17
|
folder = nil
|
@@ -5,7 +5,9 @@ require "imap/backup/serializer/imap"
|
|
5
5
|
module Imap; end
|
6
6
|
|
7
7
|
module Imap::Backup
|
8
|
+
# Migrates serialized folder metadata from the version 2 format to the version 3 format
|
8
9
|
class Serializer::Version2Migrator
|
10
|
+
# @param folder_path [String] the base pathv(without extension) of the folder backup
|
9
11
|
def initialize(folder_path)
|
10
12
|
@folder_path = folder_path
|
11
13
|
end
|
@@ -21,6 +23,8 @@ module Imap::Backup
|
|
21
23
|
true
|
22
24
|
end
|
23
25
|
|
26
|
+
# Runs the migration
|
27
|
+
# @return [Boolean] whether the migration was run
|
24
28
|
def run
|
25
29
|
return false if !required?
|
26
30
|
|
@@ -15,7 +15,11 @@ require "imap/backup/serializer/unused_name_finder"
|
|
15
15
|
module Imap; end
|
16
16
|
|
17
17
|
module Imap::Backup
|
18
|
+
# Handles serialization for a folder
|
18
19
|
class Serializer
|
20
|
+
# @param path [String] an account's backup path
|
21
|
+
# @param folder [String] a folder name
|
22
|
+
# @return [String] the full path to a serialized folder (without file extensions)
|
19
23
|
def self.folder_path_for(path:, folder:)
|
20
24
|
relative = File.join(path, folder)
|
21
25
|
File.expand_path(relative)
|
@@ -26,9 +30,13 @@ module Imap::Backup
|
|
26
30
|
def_delegator :mbox, :pathname, :mbox_pathname
|
27
31
|
def_delegators :imap, :get, :messages, :uid_validity, :uids, :update_uid
|
28
32
|
|
33
|
+
# @return [String] a folder name
|
29
34
|
attr_reader :folder
|
35
|
+
# @return [String] an account's backup path
|
30
36
|
attr_reader :path
|
31
37
|
|
38
|
+
# @param path [String] an account's backup path
|
39
|
+
# @param folder [String] a folder name
|
32
40
|
def initialize(path, folder)
|
33
41
|
@path = path
|
34
42
|
@folder = folder
|
@@ -38,14 +46,17 @@ module Imap::Backup
|
|
38
46
|
# Calls the supplied block.
|
39
47
|
# This method is present so that this class implements the same
|
40
48
|
# interface as {DelayedMetadataSerializer}
|
49
|
+
# @param block [block] the block that is wrapped by the transaction
|
41
50
|
#
|
42
51
|
# @return [void]
|
43
52
|
def transaction(&block)
|
44
53
|
block.call
|
45
54
|
end
|
46
55
|
|
47
|
-
#
|
48
|
-
#
|
56
|
+
# Checks that the metadata files are valid, migrates the metadata file
|
57
|
+
# from older versions, if necessary,
|
58
|
+
# or deletes any existing files if the pair are not valid.
|
59
|
+
# @return [Boolean] indicates whether there are existing, valid files
|
49
60
|
def validate!
|
50
61
|
return true if @validated
|
51
62
|
|
@@ -61,16 +72,33 @@ module Imap::Backup
|
|
61
72
|
false
|
62
73
|
end
|
63
74
|
|
75
|
+
# Checks that the folder's data is stored correctly
|
76
|
+
# @return [void]
|
64
77
|
def check_integrity!
|
65
78
|
IntegrityChecker.new(imap: imap, mbox: mbox).run
|
66
79
|
end
|
67
80
|
|
81
|
+
# Deletes the serialized data
|
82
|
+
# @return [void]
|
68
83
|
def delete
|
69
84
|
imap.delete
|
70
85
|
mbox.delete
|
71
86
|
reload
|
72
87
|
end
|
73
88
|
|
89
|
+
# Sets the folder's UID validity.
|
90
|
+
# If the existing value is nil, it sets the new value
|
91
|
+
# and ensures that both the metadata file and the mailbox
|
92
|
+
# are saved.
|
93
|
+
# If the supplied value is the same as the existing value,
|
94
|
+
# it does nothing.
|
95
|
+
# If the supplied valued is *different* to the existing value,
|
96
|
+
# it renames the existing folder to a new name, and creates a
|
97
|
+
# new folder with the supplied value.
|
98
|
+
#
|
99
|
+
# @param value [Integer] The new UID validity value
|
100
|
+
#
|
101
|
+
# @return [String, nil] The name of the new folder
|
74
102
|
def apply_uid_validity(value)
|
75
103
|
validate!
|
76
104
|
|
@@ -86,12 +114,22 @@ module Imap::Backup
|
|
86
114
|
end
|
87
115
|
end
|
88
116
|
|
117
|
+
# Overwrites the UID validity of the folder
|
118
|
+
# and ensures that both the metadata file and the mailbox
|
119
|
+
# are saved.
|
120
|
+
# @param value [Integer] the new UID validity
|
121
|
+
# @return [void]
|
89
122
|
def force_uid_validity(value)
|
90
123
|
validate!
|
91
124
|
|
92
125
|
internal_force_uid_validity(value)
|
93
126
|
end
|
94
127
|
|
128
|
+
# Appends a message to the serialized data
|
129
|
+
# @param uid [Integer] the message's UID
|
130
|
+
# @param message [Integer] the message text
|
131
|
+
# @param flags [Array[Symbol]] the message's flags
|
132
|
+
# @return [void]
|
95
133
|
def append(uid, message, flags)
|
96
134
|
validate!
|
97
135
|
|
@@ -99,6 +137,10 @@ module Imap::Backup
|
|
99
137
|
appender.append(uid: uid, message: message, flags: flags)
|
100
138
|
end
|
101
139
|
|
140
|
+
# Updates a messages flags
|
141
|
+
# @param uid [Integer] the message's UID
|
142
|
+
# @param flags [Array<Symbol>] the flags to set on the message
|
143
|
+
# @return [void]
|
102
144
|
def update(uid, flags: nil)
|
103
145
|
message = imap.get(uid)
|
104
146
|
return if !message
|
@@ -107,6 +149,10 @@ module Imap::Backup
|
|
107
149
|
imap.save
|
108
150
|
end
|
109
151
|
|
152
|
+
# Enumerates over a series of messages.
|
153
|
+
# When called without a block, returns an Enumerator
|
154
|
+
# @param required_uids [Array<Integer>] the UIDs of the message to enumerate over
|
155
|
+
# @return [Enumerator, void]
|
110
156
|
def each_message(required_uids = nil, &block)
|
111
157
|
return enum_for(:each_message, required_uids) if !block
|
112
158
|
|
@@ -118,6 +164,10 @@ module Imap::Backup
|
|
118
164
|
enumerator.run(uids: required_uids, &block)
|
119
165
|
end
|
120
166
|
|
167
|
+
# Calls the supplied block on each message in the folder
|
168
|
+
# and discards those for which the block returns a false result
|
169
|
+
# @param block [block] the block to call
|
170
|
+
# @return [void]
|
121
171
|
def filter(&block)
|
122
172
|
temp_name = Serializer::UnusedNameFinder.new(serializer: self).run
|
123
173
|
temp_folder_path = self.class.folder_path_for(path: path, folder: temp_name)
|
@@ -137,14 +187,18 @@ module Imap::Backup
|
|
137
187
|
reload
|
138
188
|
end
|
139
189
|
|
190
|
+
# @return [String] the path to the serialized folder (without file extensions)
|
140
191
|
def folder_path
|
141
192
|
self.class.folder_path_for(path: path, folder: sanitized)
|
142
193
|
end
|
143
194
|
|
195
|
+
# @return [String] The folder's name adapted for using as a file name
|
144
196
|
def sanitized
|
145
197
|
@sanitized ||= Naming.to_local_path(folder)
|
146
198
|
end
|
147
199
|
|
200
|
+
# Forces a reload of the serialized files
|
201
|
+
# @return [void]
|
148
202
|
def reload
|
149
203
|
@imap = nil
|
150
204
|
@mbox = nil
|
@@ -8,12 +8,18 @@ module Imap::Backup
|
|
8
8
|
class Setup; end
|
9
9
|
class Setup::Account; end
|
10
10
|
|
11
|
+
# Displays the header to the account modification menu
|
11
12
|
class Setup::Account::Header
|
13
|
+
# @param menu [Highline::Menu] the menu
|
14
|
+
# @param account [Account] an Account
|
12
15
|
def initialize(menu:, account:)
|
13
16
|
@menu = menu
|
14
17
|
@account = account
|
15
18
|
end
|
16
19
|
|
20
|
+
# Displays the header
|
21
|
+
#
|
22
|
+
# @return [void]
|
17
23
|
def run
|
18
24
|
rows = [
|
19
25
|
email,
|
@@ -10,13 +10,19 @@ module Imap; end
|
|
10
10
|
module Imap::Backup
|
11
11
|
class Setup; end
|
12
12
|
|
13
|
+
# Handles interactive account setup
|
13
14
|
class Setup::Account
|
15
|
+
# @param config [Configuration] the application configuration
|
16
|
+
# @param account [Account] an Account
|
17
|
+
# @param highline [Higline] the configured Highline instance
|
14
18
|
def initialize(config, account, highline)
|
15
19
|
@account = account
|
16
20
|
@config = config
|
17
21
|
@highline = highline
|
18
22
|
end
|
19
23
|
|
24
|
+
# Shows the menu
|
25
|
+
# @return [void]
|
20
26
|
def run
|
21
27
|
if !account.local_path
|
22
28
|
account.local_path = File.join(config.path, account.username.tr("@", "_"))
|
@@ -3,11 +3,17 @@ module Imap; end
|
|
3
3
|
module Imap::Backup
|
4
4
|
class Setup; end
|
5
5
|
|
6
|
+
# Implements interactively requesting information from the user
|
6
7
|
class Setup::Asker
|
8
|
+
# @param highline [Higline] the configured Highline instance
|
7
9
|
def initialize(highline)
|
8
10
|
@highline = highline
|
9
11
|
end
|
10
12
|
|
13
|
+
# Asks for a email address
|
14
|
+
#
|
15
|
+
# @param default [String] the existing email address
|
16
|
+
# @return [String] the email address
|
11
17
|
def email(default = "")
|
12
18
|
highline.ask("email address: ") do |q|
|
13
19
|
q.default = default
|
@@ -16,6 +22,9 @@ module Imap::Backup
|
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
25
|
+
# Asks for a password
|
26
|
+
#
|
27
|
+
# @return [String] the password
|
19
28
|
def password
|
20
29
|
password = highline.ask("password: ") { |q| q.echo = false }
|
21
30
|
confirmation = highline.ask("repeat password: ") { |q| q.echo = false }
|
@@ -29,10 +38,17 @@ module Imap::Backup
|
|
29
38
|
password
|
30
39
|
end
|
31
40
|
|
41
|
+
# Asks for a email address using the configured menu handler
|
42
|
+
#
|
43
|
+
# @param default [String] the existing email address
|
44
|
+
# @return [String] the email address
|
32
45
|
def self.email(default = "")
|
33
46
|
new(Setup.highline).email(default)
|
34
47
|
end
|
35
48
|
|
49
|
+
# Asks for a password using the configured menu handler
|
50
|
+
#
|
51
|
+
# @return [String] the password
|
36
52
|
def self.password
|
37
53
|
new(Setup.highline).password
|
38
54
|
end
|
@@ -3,12 +3,18 @@ module Imap; end
|
|
3
3
|
module Imap::Backup
|
4
4
|
class Setup; end
|
5
5
|
|
6
|
+
# Requests an updated backup path from the user
|
6
7
|
class Setup::BackupPath
|
8
|
+
# @param account [Account] an Account
|
9
|
+
# @param config [Configuration] the application configuration
|
7
10
|
def initialize(account:, config:)
|
8
11
|
@account = account
|
9
12
|
@config = config
|
10
13
|
end
|
11
14
|
|
15
|
+
# Asks the user for a backup path
|
16
|
+
#
|
17
|
+
# @return [void]
|
12
18
|
def run
|
13
19
|
account.local_path = highline.ask("backup directory: ") do |q|
|
14
20
|
q.default = account.local_path
|
@@ -5,11 +5,16 @@ module Imap; end
|
|
5
5
|
module Imap::Backup
|
6
6
|
class Setup; end
|
7
7
|
|
8
|
+
# Attempts to login to an account and reports the result
|
8
9
|
class Setup::ConnectionTester
|
10
|
+
# @param account [Account] an Account
|
9
11
|
def initialize(account)
|
10
12
|
@account = account
|
11
13
|
end
|
12
14
|
|
15
|
+
# Carries out the attempted login and indicates
|
16
|
+
# whether it was successful
|
17
|
+
# @return [void]
|
13
18
|
def test
|
14
19
|
account.client.login
|
15
20
|
"Connection successful"
|
@@ -6,12 +6,18 @@ module Imap; end
|
|
6
6
|
module Imap::Backup
|
7
7
|
class Setup; end
|
8
8
|
|
9
|
+
# Asks the user for a new email address
|
9
10
|
class Setup::EmailChanger
|
11
|
+
# @param account [Account] an Account
|
12
|
+
# @param config [Configuration] the application configuration
|
10
13
|
def initialize(account:, config:)
|
11
14
|
@account = account
|
12
15
|
@config = config
|
13
16
|
end
|
14
17
|
|
18
|
+
# Asks the user for an email address,
|
19
|
+
# ensuring that the supplied address is not an existing account
|
20
|
+
# @return [void]
|
15
21
|
def run
|
16
22
|
username = Setup::Asker.email(account.username)
|
17
23
|
other_accounts = config.accounts.reject { |a| a == account }
|
@@ -5,11 +5,15 @@ module Imap; end
|
|
5
5
|
module Imap::Backup
|
6
6
|
class Setup; end
|
7
7
|
|
8
|
+
# Allows the user to select and deselect folders to be backed up
|
8
9
|
class Setup::FolderChooser
|
10
|
+
# @param account [Account] an Account
|
9
11
|
def initialize(account)
|
10
12
|
@account = account
|
11
13
|
end
|
12
14
|
|
15
|
+
# Lists account folders and allows the user to toggle whther they are selected
|
16
|
+
# @return [void]
|
13
17
|
def run
|
14
18
|
if client.nil?
|
15
19
|
highline.ask "Press a key "
|
@@ -5,11 +5,15 @@ module Imap::Backup; end
|
|
5
5
|
class Imap::Backup::Setup; end
|
6
6
|
|
7
7
|
class Imap::Backup::Setup::GlobalOptions
|
8
|
+
# Allows changing the globally configured download strategy
|
8
9
|
class DownloadStrategyChooser
|
10
|
+
# @param config [Configuration] the application configuration
|
9
11
|
def initialize(config:)
|
10
12
|
@config = config
|
11
13
|
end
|
12
14
|
|
15
|
+
# Shows the menu
|
16
|
+
# @return [void]
|
13
17
|
def run
|
14
18
|
catch :done do
|
15
19
|
loop do
|
@@ -6,11 +6,15 @@ module Imap; end
|
|
6
6
|
module Imap::Backup
|
7
7
|
class Setup; end
|
8
8
|
|
9
|
+
# Shows the menu of global options
|
9
10
|
class Setup::GlobalOptions
|
11
|
+
# @param config [Configuration] the application configuration
|
10
12
|
def initialize(config:)
|
11
13
|
@config = config
|
12
14
|
end
|
13
15
|
|
16
|
+
# Shows the menu
|
17
|
+
# @return [void]
|
14
18
|
def run
|
15
19
|
catch :done do
|
16
20
|
loop do
|
@@ -5,11 +5,14 @@ module Imap; end
|
|
5
5
|
module Imap::Backup
|
6
6
|
class Setup; end
|
7
7
|
|
8
|
+
# Helpers for the setup system
|
8
9
|
class Setup::Helpers
|
10
|
+
# @return [String] the prefix for setup menus
|
9
11
|
def title_prefix
|
10
12
|
"imap-backup -"
|
11
13
|
end
|
12
14
|
|
15
|
+
# @return [String] the current application version
|
13
16
|
def version
|
14
17
|
VERSION
|
15
18
|
end
|
data/lib/imap/backup/setup.rb
CHANGED
@@ -10,16 +10,21 @@ require "imap/backup/setup/helpers"
|
|
10
10
|
module Imap; end
|
11
11
|
|
12
12
|
module Imap::Backup
|
13
|
+
# Interactively updates the application's configuration file
|
13
14
|
class Setup
|
14
15
|
class << self
|
16
|
+
# @return [Highline]
|
15
17
|
attr_accessor :highline
|
16
18
|
end
|
17
19
|
self.highline = HighLine.new
|
18
20
|
|
21
|
+
# @param config [Configuration] the application configuration
|
19
22
|
def initialize(config:)
|
20
23
|
@config = config
|
21
24
|
end
|
22
25
|
|
26
|
+
# Shows the menu
|
27
|
+
# @return [void]
|
23
28
|
def run
|
24
29
|
catch :done do
|
25
30
|
loop do
|
@@ -5,17 +5,24 @@ module Imap; end
|
|
5
5
|
module Imap::Backup
|
6
6
|
module Text; end
|
7
7
|
|
8
|
+
# Wraps standard output and hides passwords from debug output
|
9
|
+
# Any text matching Net::IMAP debug output of passwords is sanitized
|
8
10
|
class Text::Sanitizer
|
9
11
|
extend Forwardable
|
10
12
|
|
11
13
|
delegate puts: :output
|
12
14
|
delegate write: :output
|
13
15
|
|
16
|
+
# @param output [IO] the stream to write output to
|
14
17
|
def initialize(output)
|
15
18
|
@output = output
|
16
19
|
@current = ""
|
17
20
|
end
|
18
21
|
|
22
|
+
# Outputs everything up to the last newline character,
|
23
|
+
# storing whatever follows the newline.
|
24
|
+
# @param args [Array<String>] lines of text
|
25
|
+
# @return [void]
|
19
26
|
def print(*args)
|
20
27
|
@current << args.join
|
21
28
|
loop do
|
@@ -28,6 +35,8 @@ module Imap::Backup
|
|
28
35
|
end
|
29
36
|
end
|
30
37
|
|
38
|
+
# Outputs any text still not printed
|
39
|
+
# @return [void]
|
31
40
|
def flush
|
32
41
|
return if @current == ""
|
33
42
|
|
@@ -7,7 +7,11 @@ module Imap; end
|
|
7
7
|
module Imap::Backup
|
8
8
|
class Thunderbird; end
|
9
9
|
|
10
|
+
# Exports an account's emails to Thunderbird
|
10
11
|
class Thunderbird::MailboxExporter
|
12
|
+
# @param email [String] an email address
|
13
|
+
# @param serializer [Serializer] a local folder backup
|
14
|
+
# @param profile [Thunderbird::Profile] an existing Thunderbird profile
|
11
15
|
def initialize(email, serializer, profile, force: false)
|
12
16
|
@email = email
|
13
17
|
@serializer = serializer
|
@@ -15,6 +19,9 @@ module Imap::Backup
|
|
15
19
|
@force = force
|
16
20
|
end
|
17
21
|
|
22
|
+
# Copies the account's messages to the Thunderbird directory
|
23
|
+
# in the format expected by Thunderbird
|
24
|
+
# @return [void]
|
18
25
|
def run
|
19
26
|
if !profile_set_up
|
20
27
|
error "The Thunderbird profile '#{profile.title}' " \
|
data/lib/imap/backup/uploader.rb
CHANGED
@@ -5,12 +5,17 @@ require "imap/backup/serializer"
|
|
5
5
|
module Imap; end
|
6
6
|
|
7
7
|
module Imap::Backup
|
8
|
+
# Uploads a backed-up folder
|
8
9
|
class Uploader
|
10
|
+
# @param folder [Account::Folder] an online folder
|
11
|
+
# @param serializer [Serializer] a local folder backup
|
9
12
|
def initialize(folder, serializer)
|
10
13
|
@folder = folder
|
11
14
|
@serializer = serializer
|
12
15
|
end
|
13
16
|
|
17
|
+
# Uploads messages that are present in the backup, but not in the online folder
|
18
|
+
# @return [void]
|
14
19
|
def run
|
15
20
|
if folder.uids.any?
|
16
21
|
rename_serialized_folder
|
data/lib/imap/backup/version.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
module Imap; end
|
2
2
|
|
3
3
|
module Imap::Backup
|
4
|
+
# @private
|
4
5
|
MAJOR = 14
|
6
|
+
# @private
|
5
7
|
MINOR = 4
|
6
|
-
|
8
|
+
# @private
|
9
|
+
REVISION = 5
|
10
|
+
# @private
|
7
11
|
PRE = nil
|
12
|
+
# The application version
|
8
13
|
VERSION = [MAJOR, MINOR, REVISION, PRE].compact.map(&:to_s).join(".")
|
9
14
|
end
|
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: 14.4.
|
4
|
+
version: 14.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Yates
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -133,10 +133,8 @@ files:
|
|
133
133
|
- LICENSE
|
134
134
|
- README.md
|
135
135
|
- bin/imap-backup
|
136
|
-
- docs/api.md
|
137
136
|
- docs/delimiters-and-prefixes.md
|
138
|
-
- docs/
|
139
|
-
- docs/migrate-server-keep-address.md
|
137
|
+
- docs/documentation.md
|
140
138
|
- docs/performance.md
|
141
139
|
- imap-backup.gemspec
|
142
140
|
- lib/imap/backup/account.rb
|
data/docs/api.md
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# @title Index
|
2
|
-
# imap-backup API Documentation
|
3
|
-
|
4
|
-
![Version](https://img.shields.io/gem/v/imap-backup?label=Version&logo=rubygems)
|
5
|
-
[![Build Status](https://github.com/joeyates/imap-backup/actions/workflows/main.yml/badge.svg)][CI Status]
|
6
|
-
![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/joeyates/b54fe758bfb405c04bef72dad293d707/raw/coverage.json)
|
7
|
-
![License](https://img.shields.io/github/license/joeyates/imap-backup?color=brightgreen&label=License)
|
8
|
-
[![Stars](https://img.shields.io/github/stars/joeyates/imap-backup?style=social)][GitHub Stars]
|
9
|
-
|
10
|
-
[CI Status]: https://github.com/joeyates/imap-backup/actions/workflows/main.yml
|
11
|
-
[GitHub Stars]: https://github.com/joeyates/imap-backup/stargazers "GitHub Stars"
|
12
|
-
|
13
|
-
This is the developer documentation for imap-backup's **code**.
|
14
|
-
|
15
|
-
Usage documentation is on [GitHub](https://github.com/joeyates/imap-backup).
|
16
|
-
|
17
|
-
You can get an overview of the program's structure from the
|
18
|
-
{file:ARCHITECTURE.md ARCHITECTURE} file.
|
19
|
-
|
20
|
-
The {file:CHANGELOG.md CHANGELOG} has a history of the changes to the program.
|