imap-backup 1.2.2 → 1.2.3
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/.rubocop.yml +7 -0
- data/Gemfile +1 -1
- data/Rakefile +4 -4
- data/bin/imap-backup +23 -25
- data/imap-backup.gemspec +14 -14
- data/lib/email/mboxrd/message.rb +23 -5
- data/lib/email/provider.rb +4 -4
- data/lib/imap/backup.rb +18 -18
- data/lib/imap/backup/account/connection.rb +6 -6
- data/lib/imap/backup/account/folder.rb +4 -5
- data/lib/imap/backup/configuration/account.rb +20 -22
- data/lib/imap/backup/configuration/asker.rb +8 -10
- data/lib/imap/backup/configuration/connection_tester.rb +3 -5
- data/lib/imap/backup/configuration/folder_chooser.rb +10 -12
- data/lib/imap/backup/configuration/list.rb +1 -3
- data/lib/imap/backup/configuration/setup.rb +13 -14
- data/lib/imap/backup/configuration/store.rb +7 -8
- data/lib/imap/backup/downloader.rb +0 -2
- data/lib/imap/backup/serializer/base.rb +0 -2
- data/lib/imap/backup/serializer/directory.rb +3 -4
- data/lib/imap/backup/serializer/mbox.rb +11 -12
- data/lib/imap/backup/utils.rb +2 -3
- data/lib/imap/backup/version.rb +2 -2
- data/spec/spec_helper.rb +6 -6
- data/spec/support/higline_test_helpers.rb +1 -1
- data/spec/support/shared_examples/account_flagging.rb +6 -6
- data/spec/unit/account/connection_spec.rb +50 -51
- data/spec/unit/account/folder_spec.rb +18 -19
- data/spec/unit/configuration/account_spec.rb +96 -97
- data/spec/unit/configuration/asker_spec.rb +33 -34
- data/spec/unit/configuration/connection_tester_spec.rb +18 -19
- data/spec/unit/configuration/folder_chooser_spec.rb +34 -35
- data/spec/unit/configuration/list_spec.rb +13 -14
- data/spec/unit/configuration/setup_spec.rb +46 -47
- data/spec/unit/configuration/store_spec.rb +56 -57
- data/spec/unit/downloader_spec.rb +18 -19
- data/spec/unit/email/mboxrd/message_spec.rb +55 -11
- data/spec/unit/email/provider_spec.rb +12 -12
- data/spec/unit/serializer/base_spec.rb +7 -9
- data/spec/unit/serializer/directory_spec.rb +18 -19
- data/spec/unit/serializer/mbox_spec.rb +35 -37
- data/spec/unit/utils_spec.rb +26 -27
- metadata +17 -2
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Imap::Backup
|
4
2
|
module Configuration; end
|
5
3
|
|
@@ -10,18 +8,18 @@ module Imap::Backup
|
|
10
8
|
super
|
11
9
|
end
|
12
10
|
|
13
|
-
def email(default =
|
14
|
-
highline.ask(
|
11
|
+
def email(default = "")
|
12
|
+
highline.ask("email address: ") do |q|
|
15
13
|
q.default = default
|
16
14
|
q.readline = true
|
17
15
|
q.validate = EMAIL_MATCHER
|
18
|
-
q.responses[:not_valid] =
|
16
|
+
q.responses[:not_valid] = "Enter a valid email address "
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
20
|
def password
|
23
|
-
password = highline.ask(
|
24
|
-
confirmation = highline.ask(
|
21
|
+
password = highline.ask("password: ") { |q| q.echo = false }
|
22
|
+
confirmation = highline.ask("repeat password: ") { |q| q.echo = false }
|
25
23
|
if password != confirmation
|
26
24
|
return nil unless highline.agree("the password and confirmation did not match.\nContinue? (y/n) ")
|
27
25
|
return self.password
|
@@ -30,15 +28,15 @@ module Imap::Backup
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def backup_path(default, validator)
|
33
|
-
highline.ask(
|
31
|
+
highline.ask("backup directory: ") do |q|
|
34
32
|
q.default = default
|
35
33
|
q.readline = true
|
36
34
|
q.validate = validator
|
37
|
-
q.responses[:not_valid] =
|
35
|
+
q.responses[:not_valid] = "Choose a different directory "
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
|
-
def self.email(default =
|
39
|
+
def self.email(default = "")
|
42
40
|
new(Configuration::Setup.highline).email(default)
|
43
41
|
end
|
44
42
|
|
@@ -1,16 +1,14 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Imap::Backup
|
4
2
|
module Configuration; end
|
5
3
|
|
6
4
|
module Configuration::ConnectionTester
|
7
5
|
def self.test(account)
|
8
6
|
Account::Connection.new(account).imap
|
9
|
-
|
7
|
+
"Connection successful"
|
10
8
|
rescue Net::IMAP::NoResponseError
|
11
|
-
|
9
|
+
"No response"
|
12
10
|
rescue Exception => e
|
13
|
-
|
11
|
+
"Unexpected error: #{e}"
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Imap::Backup
|
4
2
|
module Configuration; end
|
5
3
|
|
@@ -12,20 +10,20 @@ module Imap::Backup
|
|
12
10
|
|
13
11
|
def run
|
14
12
|
if connection.nil?
|
15
|
-
Imap::Backup.logger.warn
|
16
|
-
highline.ask
|
13
|
+
Imap::Backup.logger.warn "Connection failed"
|
14
|
+
highline.ask "Press a key "
|
17
15
|
return
|
18
16
|
end
|
19
17
|
|
20
18
|
if folders.nil?
|
21
|
-
Imap::Backup.logger.warn
|
22
|
-
highline.ask
|
19
|
+
Imap::Backup.logger.warn "Unable to get folder list"
|
20
|
+
highline.ask "Press a key "
|
23
21
|
return
|
24
22
|
end
|
25
23
|
|
26
24
|
catch :done do
|
27
25
|
loop do
|
28
|
-
system(
|
26
|
+
system("clear")
|
29
27
|
show_menu
|
30
28
|
end
|
31
29
|
end
|
@@ -35,18 +33,18 @@ module Imap::Backup
|
|
35
33
|
|
36
34
|
def show_menu
|
37
35
|
highline.choose do |menu|
|
38
|
-
menu.header =
|
36
|
+
menu.header = "Add/remove folders"
|
39
37
|
menu.index = :number
|
40
38
|
add_folders menu
|
41
|
-
menu.choice(
|
42
|
-
menu.hidden(
|
39
|
+
menu.choice("return to the account menu") { throw :done }
|
40
|
+
menu.hidden("quit") { throw :done }
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
def add_folders(menu)
|
47
45
|
folders.each do |folder|
|
48
46
|
name = folder.name
|
49
|
-
mark = is_selected?(name) ?
|
47
|
+
mark = is_selected?(name) ? "+" : "-"
|
50
48
|
menu.choice("#{mark} #{name}") do
|
51
49
|
toggle_selection name
|
52
50
|
end
|
@@ -62,7 +60,7 @@ module Imap::Backup
|
|
62
60
|
changed = account[:folders].reject! { |f| f[:name] == folder_name }
|
63
61
|
account[:modified] = true if changed
|
64
62
|
else
|
65
|
-
account[:folders] << {
|
63
|
+
account[:folders] << {name: folder_name}
|
66
64
|
account[:modified] = true
|
67
65
|
end
|
68
66
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Imap::Backup
|
4
2
|
module Configuration; end
|
5
3
|
|
@@ -42,7 +40,7 @@ module Imap::Backup
|
|
42
40
|
if required_accounts.nil?
|
43
41
|
@accounts = config.accounts
|
44
42
|
else
|
45
|
-
@accounts = config.accounts.select{ |account| required_accounts.include?(account[:username]) }
|
43
|
+
@accounts = config.accounts.select { |account| required_accounts.include?(account[:username]) }
|
46
44
|
end
|
47
45
|
end
|
48
46
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'highline'
|
1
|
+
require "highline"
|
3
2
|
|
4
3
|
module Imap::Backup
|
5
4
|
module Configuration; end
|
@@ -14,7 +13,7 @@ module Imap::Backup
|
|
14
13
|
Imap::Backup.setup_logging config
|
15
14
|
catch :done do
|
16
15
|
loop do
|
17
|
-
system(
|
16
|
+
system("clear")
|
18
17
|
show_menu
|
19
18
|
end
|
20
19
|
end
|
@@ -24,15 +23,15 @@ module Imap::Backup
|
|
24
23
|
|
25
24
|
def show_menu
|
26
25
|
self.class.highline.choose do |menu|
|
27
|
-
menu.header =
|
26
|
+
menu.header = "Choose an action"
|
28
27
|
account_items menu
|
29
28
|
add_account_item menu
|
30
29
|
toggle_logging_item menu
|
31
|
-
menu.choice(
|
30
|
+
menu.choice("save and exit") do
|
32
31
|
config.save
|
33
32
|
throw :done
|
34
33
|
end
|
35
|
-
menu.choice(
|
34
|
+
menu.choice("exit without saving changes") do
|
36
35
|
throw :done
|
37
36
|
end
|
38
37
|
end
|
@@ -42,7 +41,7 @@ module Imap::Backup
|
|
42
41
|
config.accounts.each do |account|
|
43
42
|
next if account[:delete]
|
44
43
|
item = account[:username].clone
|
45
|
-
item <<
|
44
|
+
item << " *" if account[:modified]
|
46
45
|
menu.choice(item) do
|
47
46
|
edit_account account[:username]
|
48
47
|
end
|
@@ -50,15 +49,15 @@ module Imap::Backup
|
|
50
49
|
end
|
51
50
|
|
52
51
|
def add_account_item(menu)
|
53
|
-
menu.choice(
|
52
|
+
menu.choice("add account") do
|
54
53
|
username = Configuration::Asker.email
|
55
54
|
edit_account username
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
59
58
|
def toggle_logging_item(menu)
|
60
|
-
menu_item = config.debug? ?
|
61
|
-
new_setting = !
|
59
|
+
menu_item = config.debug? ? "stop logging" : "start logging"
|
60
|
+
new_setting = !config.debug?
|
62
61
|
menu.choice(menu_item) do
|
63
62
|
config.debug = new_setting
|
64
63
|
Imap::Backup.setup_logging config
|
@@ -71,10 +70,10 @@ module Imap::Backup
|
|
71
70
|
|
72
71
|
def default_account_config(username)
|
73
72
|
account = {
|
74
|
-
:
|
75
|
-
:
|
76
|
-
:
|
77
|
-
:
|
73
|
+
username: username,
|
74
|
+
password: "",
|
75
|
+
local_path: File.join(config.path, username.gsub("@", "_")),
|
76
|
+
folders: []
|
78
77
|
}
|
79
78
|
end
|
80
79
|
|
@@ -1,16 +1,15 @@
|
|
1
|
-
|
2
|
-
require 'json'
|
1
|
+
require "json"
|
3
2
|
|
4
3
|
module Imap::Backup
|
5
4
|
module Configuration; end
|
6
5
|
|
7
6
|
class Configuration::Store
|
8
|
-
CONFIGURATION_DIRECTORY = File.expand_path(
|
7
|
+
CONFIGURATION_DIRECTORY = File.expand_path("~/.imap-backup")
|
9
8
|
|
10
9
|
attr_reader :pathname
|
11
10
|
|
12
11
|
def self.default_pathname
|
13
|
-
File.join(CONFIGURATION_DIRECTORY,
|
12
|
+
File.join(CONFIGURATION_DIRECTORY, "config.json")
|
14
13
|
end
|
15
14
|
|
16
15
|
def self.exist?(pathname = default_pathname)
|
@@ -29,7 +28,7 @@ module Imap::Backup
|
|
29
28
|
mkdir_private path
|
30
29
|
remove_modified_flags
|
31
30
|
remove_deleted_accounts
|
32
|
-
File.open(pathname,
|
31
|
+
File.open(pathname, "w") { |f| f.write(JSON.pretty_generate(data)) }
|
33
32
|
FileUtils.chmod 0600, pathname
|
34
33
|
end
|
35
34
|
|
@@ -56,9 +55,9 @@ module Imap::Backup
|
|
56
55
|
if File.exist?(pathname)
|
57
56
|
Utils.check_permissions pathname, 0600
|
58
57
|
contents = File.read(pathname)
|
59
|
-
@data = JSON.parse(contents, :
|
58
|
+
@data = JSON.parse(contents, symbolize_names: true)
|
60
59
|
else
|
61
|
-
@data = {:
|
60
|
+
@data = {accounts: []}
|
62
61
|
end
|
63
62
|
@data[:debug] = false unless @data.include?(:debug)
|
64
63
|
@data[:debug] = false unless [true, false].include?(@data[:debug])
|
@@ -74,7 +73,7 @@ module Imap::Backup
|
|
74
73
|
end
|
75
74
|
|
76
75
|
def mkdir_private(path)
|
77
|
-
if !
|
76
|
+
if !File.directory?(path)
|
78
77
|
FileUtils.mkdir path
|
79
78
|
end
|
80
79
|
if Utils::stat(path) != 0700
|
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'fileutils'
|
1
|
+
require "fileutils"
|
3
2
|
|
4
3
|
module Imap::Backup
|
5
4
|
module Serializer; end
|
@@ -11,7 +10,7 @@ module Imap::Backup
|
|
11
10
|
end
|
12
11
|
|
13
12
|
def uids
|
14
|
-
return [] if !
|
13
|
+
return [] if !File.exist?(directory)
|
15
14
|
|
16
15
|
d = Dir.open(directory)
|
17
16
|
as_strings = d.map do |file|
|
@@ -27,7 +26,7 @@ module Imap::Backup
|
|
27
26
|
|
28
27
|
def save(uid, message)
|
29
28
|
message_filename = filename(uid)
|
30
|
-
File.open(message_filename,
|
29
|
+
File.open(message_filename, "w") { |f| f.write message.to_json }
|
31
30
|
FileUtils.chmod 0600, message_filename
|
32
31
|
end
|
33
32
|
|
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
require 'email/mboxrd/message'
|
1
|
+
require "csv"
|
2
|
+
require "email/mboxrd/message"
|
4
3
|
|
5
4
|
module Imap::Backup
|
6
5
|
module Serializer; end
|
@@ -37,12 +36,12 @@ module Imap::Backup
|
|
37
36
|
# invalidate cache
|
38
37
|
@uids = nil
|
39
38
|
|
40
|
-
body = message[
|
39
|
+
body = message["RFC822"]
|
41
40
|
mboxrd_message = Email::Mboxrd::Message.new(body)
|
42
41
|
mbox = imap = nil
|
43
42
|
begin
|
44
|
-
mbox = File.open(mbox_pathname,
|
45
|
-
imap = File.open(imap_pathname,
|
43
|
+
mbox = File.open(mbox_pathname, "ab")
|
44
|
+
imap = File.open(imap_pathname, "ab")
|
46
45
|
mbox.write mboxrd_message.to_s
|
47
46
|
imap.write uid + "\n"
|
48
47
|
rescue => e
|
@@ -58,18 +57,18 @@ module Imap::Backup
|
|
58
57
|
def assert_files
|
59
58
|
mbox = mbox_exist?
|
60
59
|
imap = imap_exist?
|
61
|
-
raise
|
62
|
-
raise
|
60
|
+
raise ".imap file missing" if mbox && (not imap)
|
61
|
+
raise ".mbox file missing" if imap && (not mbox)
|
63
62
|
end
|
64
63
|
|
65
64
|
def create_containing_directory
|
66
65
|
mbox_relative_path = File.dirname(mbox_relative_pathname)
|
67
|
-
return if mbox_relative_path ==
|
66
|
+
return if mbox_relative_path == "."
|
68
67
|
Utils.make_folder(path, mbox_relative_path, Serializer::DIRECTORY_PERMISSIONS)
|
69
68
|
end
|
70
69
|
|
71
70
|
def exist?
|
72
|
-
mbox_exist?
|
71
|
+
mbox_exist? && imap_exist?
|
73
72
|
end
|
74
73
|
|
75
74
|
def mbox_exist?
|
@@ -81,7 +80,7 @@ module Imap::Backup
|
|
81
80
|
end
|
82
81
|
|
83
82
|
def mbox_relative_pathname
|
84
|
-
folder +
|
83
|
+
folder + ".mbox"
|
85
84
|
end
|
86
85
|
|
87
86
|
def mbox_pathname
|
@@ -89,7 +88,7 @@ module Imap::Backup
|
|
89
88
|
end
|
90
89
|
|
91
90
|
def imap_pathname
|
92
|
-
filename = folder +
|
91
|
+
filename = folder + ".imap"
|
93
92
|
File.join(path, filename)
|
94
93
|
end
|
95
94
|
|
data/lib/imap/backup/utils.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'fileutils'
|
1
|
+
require "fileutils"
|
3
2
|
|
4
3
|
module Imap::Backup
|
5
4
|
module Utils
|
@@ -20,7 +19,7 @@ module Imap::Backup
|
|
20
19
|
end
|
21
20
|
|
22
21
|
def self.make_folder(base_path, path, permissions)
|
23
|
-
parts = path.split(
|
22
|
+
parts = path.split("/")
|
24
23
|
return if parts.size == 0
|
25
24
|
full_path = File.join(base_path, path)
|
26
25
|
FileUtils.mkdir_p full_path
|
data/lib/imap/backup/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
require "codeclimate-test-reporter"
|
2
|
-
require
|
2
|
+
require "rspec"
|
3
3
|
|
4
4
|
CodeClimate::TestReporter.start
|
5
5
|
|
6
6
|
spec_path = File.dirname(__FILE__)
|
7
|
-
$LOAD_PATH << File.expand_path(
|
7
|
+
$LOAD_PATH << File.expand_path("../lib", spec_path)
|
8
8
|
|
9
|
-
support_glob = File.join(spec_path,
|
9
|
+
support_glob = File.join(spec_path, "support", "**", "*.rb")
|
10
10
|
Dir[support_glob].each { |f| require f }
|
11
11
|
|
12
|
-
require
|
12
|
+
require "simplecov"
|
13
13
|
SimpleCov.start do
|
14
|
-
add_filter
|
14
|
+
add_filter "/spec/"
|
15
15
|
end
|
16
16
|
|
17
|
-
require
|
17
|
+
require "imap/backup"
|
18
18
|
|
19
19
|
silence_logging
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module HighLineTestHelpers
|
2
2
|
def prepare_highline
|
3
|
-
@input = double(
|
3
|
+
@input = double("stdin", eof?: false, gets: "q\n")
|
4
4
|
@output = StringIO.new
|
5
5
|
Imap::Backup::Configuration::Setup.highline = HighLine.new(@input, @output)
|
6
6
|
[@input, @output]
|
@@ -1,23 +1,23 @@
|
|
1
|
-
shared_examples
|
2
|
-
it
|
1
|
+
shared_examples "it flags the account as modified" do
|
2
|
+
it "flags that the account has changed" do
|
3
3
|
expect(account[:modified]).to be_truthy
|
4
4
|
end
|
5
5
|
end
|
6
6
|
|
7
7
|
shared_examples "it doesn't flag the account as modified" do
|
8
|
-
it
|
8
|
+
it "does not flag that the account has changed" do
|
9
9
|
expect(account[:modified]).to be_falsey
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
shared_examples
|
14
|
-
it
|
13
|
+
shared_examples "it flags the account to be deleted" do
|
14
|
+
it "flags that the account is to be deleted" do
|
15
15
|
expect(account[:delete]).to be_truthy
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
shared_examples "it doesn't flag the account to be deleted" do
|
20
|
-
it
|
20
|
+
it "does not flags that the account is to be deleted" do
|
21
21
|
expect(account[:delete]).to be_falsey
|
22
22
|
end
|
23
23
|
end
|