imap-backup 1.0.5 → 1.0.6

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +1 -1
  4. data/Gemfile +0 -1
  5. data/README.md +0 -1
  6. data/Rakefile +4 -9
  7. data/bin/imap-backup +0 -1
  8. data/imap-backup.gemspec +0 -1
  9. data/lib/email/mboxrd/message.rb +31 -32
  10. data/lib/imap/backup.rb +17 -4
  11. data/lib/imap/backup/account/connection.rb +70 -64
  12. data/lib/imap/backup/account/folder.rb +21 -26
  13. data/lib/imap/backup/configuration/account.rb +127 -73
  14. data/lib/imap/backup/configuration/asker.rb +38 -31
  15. data/lib/imap/backup/configuration/connection_tester.rb +9 -14
  16. data/lib/imap/backup/configuration/folder_chooser.rb +43 -48
  17. data/lib/imap/backup/configuration/list.rb +19 -24
  18. data/lib/imap/backup/configuration/setup.rb +56 -51
  19. data/lib/imap/backup/configuration/store.rb +47 -52
  20. data/lib/imap/backup/downloader.rb +11 -14
  21. data/lib/imap/backup/serializer/base.rb +8 -11
  22. data/lib/imap/backup/serializer/directory.rb +36 -41
  23. data/lib/imap/backup/serializer/mbox.rb +83 -88
  24. data/lib/imap/backup/utils.rb +0 -3
  25. data/lib/imap/backup/version.rb +1 -2
  26. data/spec/gather_rspec_coverage.rb +0 -1
  27. data/spec/spec_helper.rb +2 -7
  28. data/spec/unit/account/connection_spec.rb +0 -1
  29. data/spec/unit/account/folder_spec.rb +0 -1
  30. data/spec/unit/configuration/account_spec.rb +207 -136
  31. data/spec/unit/configuration/asker_spec.rb +59 -85
  32. data/spec/unit/configuration/connection_tester_spec.rb +36 -26
  33. data/spec/unit/configuration/folder_chooser_spec.rb +3 -6
  34. data/spec/unit/configuration/list_spec.rb +0 -1
  35. data/spec/unit/configuration/setup_spec.rb +8 -9
  36. data/spec/unit/configuration/store_spec.rb +1 -4
  37. data/spec/unit/downloader_spec.rb +0 -1
  38. data/spec/unit/email/mboxrd/message_spec.rb +0 -1
  39. data/spec/unit/serializer/base_spec.rb +0 -1
  40. data/spec/unit/serializer/directory_spec.rb +0 -1
  41. data/spec/unit/serializer/mbox_spec.rb +0 -1
  42. data/spec/unit/utils_spec.rb +0 -1
  43. metadata +2 -2
@@ -1,40 +1,47 @@
1
1
  # encoding: utf-8
2
2
 
3
- module Imap
4
- module Backup
5
- module Configuration
6
- module Asker
7
- EMAIL_MATCHER = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
3
+ module Imap::Backup::Configuration
4
+ class Asker < Struct.new(:highline)
5
+ EMAIL_MATCHER = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
8
6
 
9
- def self.email(default = '')
10
- Setup.highline.ask('email address: ') do |q|
11
- q.default = default
12
- q.readline = true
13
- q.validate = EMAIL_MATCHER
14
- q.responses[:not_valid] = 'Enter a valid email address '
15
- end
16
- end
7
+ def email(default = '')
8
+ highline.ask('email address: ') do |q|
9
+ q.default = default
10
+ q.readline = true
11
+ q.validate = EMAIL_MATCHER
12
+ q.responses[:not_valid] = 'Enter a valid email address '
13
+ end
14
+ end
17
15
 
18
- def self.password
19
- password = Setup.highline.ask('password: ') { |q| q.echo = false }
20
- confirmation = Setup.highline.ask('repeat password: ') { |q| q.echo = false }
21
- if password != confirmation
22
- return nil unless Setup.highline.agree("the password and confirmation did not match.\nContinue? (y/n) ")
23
- return self.password
24
- end
25
- password
26
- end
16
+ def password
17
+ password = highline.ask('password: ') { |q| q.echo = false }
18
+ confirmation = highline.ask('repeat password: ') { |q| q.echo = false }
19
+ if password != confirmation
20
+ return nil unless highline.agree("the password and confirmation did not match.\nContinue? (y/n) ")
21
+ return self.password
22
+ end
23
+ password
24
+ end
27
25
 
28
- def self.backup_path(default, validator)
29
- Setup.highline.ask('backup directory: ') do |q|
30
- q.default = default
31
- q.readline = true
32
- q.validate = validator
33
- q.responses[:not_valid] = 'Choose a different directory '
34
- end
35
- end
26
+ def backup_path(default, validator)
27
+ highline.ask('backup directory: ') do |q|
28
+ q.default = default
29
+ q.readline = true
30
+ q.validate = validator
31
+ q.responses[:not_valid] = 'Choose a different directory '
36
32
  end
37
33
  end
34
+
35
+ def self.email(default = '')
36
+ new(Setup.highline).email(default)
37
+ end
38
+
39
+ def self.password
40
+ new(Setup.highline).password
41
+ end
42
+
43
+ def self.backup_path(default, validator)
44
+ new(Setup.highline).backup_path(default, validator)
45
+ end
38
46
  end
39
47
  end
40
-
@@ -1,19 +1,14 @@
1
1
  # encoding: utf-8
2
2
 
3
- module Imap
4
- module Backup
5
- module Configuration
6
- module ConnectionTester
7
- def self.test(account)
8
- Imap::Backup::Account::Connection.new(account)
9
- return 'Connection successful'
10
- rescue Net::IMAP::NoResponseError
11
- return 'No response'
12
- rescue Exception => e
13
- return "Unexpected error: #{e}"
14
- end
15
- end
3
+ module Imap::Backup::Configuration
4
+ module ConnectionTester
5
+ def self.test(account)
6
+ Imap::Backup::Account::Connection.new(account).imap
7
+ return 'Connection successful'
8
+ rescue Net::IMAP::NoResponseError
9
+ return 'No response'
10
+ rescue Exception => e
11
+ return "Unexpected error: #{e}"
16
12
  end
17
13
  end
18
14
  end
19
-
@@ -1,60 +1,55 @@
1
1
  # encoding: utf-8
2
2
 
3
- module Imap
4
- module Backup
5
- module Configuration
6
- class FolderChooser
7
- def initialize(account)
8
- @account = account
9
- end
3
+ module Imap::Backup::Configuration
4
+ class FolderChooser
5
+ def initialize(account)
6
+ @account = account
7
+ end
10
8
 
11
- def run
12
- begin
13
- @connection = Imap::Backup::Account::Connection.new(@account)
14
- rescue => e
15
- puts 'Connection failed'
16
- Setup.highline.ask 'Press a key '
17
- return
18
- end
19
- @folders = @connection.folders
20
- if @folders.nil?
21
- puts 'Unable to get folder list'
22
- Setup.highline.ask 'Press a key '
23
- return
24
- end
25
- loop do
26
- system('clear')
27
- Setup.highline.choose do |menu|
28
- menu.header = 'Add/remove folders'
29
- menu.index = :number
30
- @folders.each do |folder|
31
- name = folder.name
32
- found = @account[:folders].find { |f| f[:name] == name }
33
- mark =
34
- if found
35
- '+'
36
- else
37
- '-'
38
- end
39
- menu.choice("#{mark} #{name}") do
40
- if found
41
- @account[:folders].reject! { |f| f[:name] == name }
42
- else
43
- @account[:folders] << { :name => name }
44
- end
45
- end
46
- end
47
- menu.choice('return to the account menu') do
48
- return
9
+ def run
10
+ begin
11
+ @connection = Imap::Backup::Account::Connection.new(@account)
12
+ rescue => e
13
+ puts 'Connection failed'
14
+ Setup.highline.ask 'Press a key '
15
+ return
16
+ end
17
+ @folders = @connection.folders
18
+ if @folders.nil?
19
+ puts 'Unable to get folder list'
20
+ Setup.highline.ask 'Press a key '
21
+ return
22
+ end
23
+ loop do
24
+ system('clear')
25
+ Setup.highline.choose do |menu|
26
+ menu.header = 'Add/remove folders'
27
+ menu.index = :number
28
+ @folders.each do |folder|
29
+ name = folder.name
30
+ found = @account[:folders].find { |f| f[:name] == name }
31
+ mark =
32
+ if found
33
+ '+'
34
+ else
35
+ '-'
49
36
  end
50
- menu.hidden('quit') do
51
- return
37
+ menu.choice("#{mark} #{name}") do
38
+ if found
39
+ @account[:folders].reject! { |f| f[:name] == name }
40
+ else
41
+ @account[:folders] << { :name => name }
52
42
  end
53
43
  end
54
44
  end
45
+ menu.choice('return to the account menu') do
46
+ return
47
+ end
48
+ menu.hidden('quit') do
49
+ return
50
+ end
55
51
  end
56
52
  end
57
53
  end
58
54
  end
59
55
  end
60
-
@@ -1,33 +1,28 @@
1
1
  # encoding: utf-8
2
2
 
3
- module Imap
4
- module Backup
5
- module Configuration
6
- class List
7
- attr_reader :accounts
3
+ module Imap::Backup::Configuration
4
+ class List
5
+ attr_reader :accounts
8
6
 
9
- def initialize(accounts = nil)
10
- if not Imap::Backup::Configuration::Store.exist?
11
- raise ConfigurationNotFound.new("Configuration file '#{Imap::Backup::Configuration::Store.default_pathname}' not found")
12
- end
13
- @config = Imap::Backup::Configuration::Store.new
7
+ def initialize(accounts = nil)
8
+ if not Imap::Backup::Configuration::Store.exist?
9
+ raise Imap::Backup::ConfigurationNotFound.new("Configuration file '#{Imap::Backup::Configuration::Store.default_pathname}' not found")
10
+ end
11
+ @config = Imap::Backup::Configuration::Store.new
14
12
 
15
- if accounts.nil?
16
- @accounts = @config.data[:accounts]
17
- else
18
- @accounts = @config.data[:accounts].select{ |account| accounts.include?(account[:username]) }
19
- end
20
- end
13
+ if accounts.nil?
14
+ @accounts = @config.data[:accounts]
15
+ else
16
+ @accounts = @config.data[:accounts].select{ |account| accounts.include?(account[:username]) }
17
+ end
18
+ end
21
19
 
22
- def each_connection
23
- @accounts.each do |account|
24
- connection = Imap::Backup::Account::Connection.new(account)
25
- yield connection
26
- connection.disconnect
27
- end
28
- end
20
+ def each_connection
21
+ @accounts.each do |account|
22
+ connection = Imap::Backup::Account::Connection.new(account)
23
+ yield connection
24
+ connection.disconnect
29
25
  end
30
26
  end
31
27
  end
32
28
  end
33
-
@@ -2,66 +2,71 @@
2
2
  require 'rubygems' if RUBY_VERSION < '1.9'
3
3
  require 'highline'
4
4
 
5
- module Imap
6
- module Backup
7
- module Configuration
8
- class Setup
9
- class << self
10
- attr_accessor :highline
11
- end
12
- self.highline = HighLine.new
13
-
14
- def initialize
15
- @config = Imap::Backup::Configuration::Store.new
16
- end
5
+ module Imap::Backup::Configuration
6
+ class Setup
7
+ class << self
8
+ attr_accessor :highline
9
+ end
10
+ self.highline = HighLine.new
17
11
 
18
- def run
19
- loop do
20
- system('clear')
21
- self.class.highline.choose do |menu|
22
- menu.header = 'Choose an action'
23
- @config.data[:accounts].each do |account|
24
- menu.choice("#{account[:username]}") do
25
- edit_account account[:username]
26
- end
27
- end
28
- menu.choice('add account') do
29
- username = Asker.email
30
- edit_account username
31
- end
32
- menu.choice('save and exit') do
33
- @config.save
34
- return
35
- end
36
- menu.choice(:quit) do
37
- return
38
- end
12
+ def run
13
+ setup_logging
14
+ loop do
15
+ system('clear')
16
+ self.class.highline.choose do |menu|
17
+ menu.header = 'Choose an action'
18
+ config.data[:accounts].each do |account|
19
+ menu.choice("#{account[:username]}") do
20
+ edit_account account[:username]
39
21
  end
40
22
  end
23
+ menu.choice('add account') do
24
+ username = Asker.email
25
+ edit_account username
26
+ end
27
+ menu.choice('save and exit') do
28
+ config.save
29
+ return
30
+ end
31
+ menu.choice(:quit) do
32
+ return
33
+ end
41
34
  end
35
+ end
36
+ end
42
37
 
43
- private
38
+ private
44
39
 
45
- def add_account(username)
46
- account = {
47
- :username => username,
48
- :password => '',
49
- :local_path => File.join(@config.path, username.gsub('@', '_')),
50
- :folders => []
51
- }
52
- @config.data[:accounts] << account
53
- account
54
- end
40
+ def config
41
+ @config ||= Imap::Backup::Configuration::Store.new
42
+ end
55
43
 
56
- def edit_account(username)
57
- account = @config.data[:accounts].find { |a| a[:username] == username }
58
- if account.nil?
59
- account = add_account(username)
60
- end
61
- Account.new(@config, account).run
44
+ def setup_logging
45
+ Imap::Backup.logger.level =
46
+ if config.data[:debug]
47
+ ::Logger::Severity::DEBUG
48
+ else
49
+ ::Logger::Severity::ERROR
62
50
  end
51
+ end
52
+
53
+ def add_account(username)
54
+ account = {
55
+ :username => username,
56
+ :password => '',
57
+ :local_path => File.join(config.path, username.gsub('@', '_')),
58
+ :folders => []
59
+ }
60
+ config.data[:accounts] << account
61
+ account
62
+ end
63
+
64
+ def edit_account(username)
65
+ account = config.data[:accounts].find { |a| a[:username] == username }
66
+ if account.nil?
67
+ account = add_account(username)
63
68
  end
69
+ Account.new(config, account, Imap::Backup::Configuration::Setup.highline).run
64
70
  end
65
71
  end
66
72
  end
67
-
@@ -2,69 +2,64 @@
2
2
  require 'rubygems' if RUBY_VERSION < '1.9'
3
3
  require 'json'
4
4
 
5
- module Imap
6
- module Backup
7
- module Configuration
8
- class Store
9
- CONFIGURATION_DIRECTORY = File.expand_path('~/.imap-backup')
5
+ module Imap::Backup::Configuration
6
+ class Store
7
+ CONFIGURATION_DIRECTORY = File.expand_path('~/.imap-backup')
10
8
 
11
- attr_reader :data
12
- attr_reader :path
9
+ attr_reader :data
10
+ attr_reader :path
13
11
 
14
- def self.default_pathname
15
- File.join(CONFIGURATION_DIRECTORY, 'config.json')
16
- end
12
+ def self.default_pathname
13
+ File.join(CONFIGURATION_DIRECTORY, 'config.json')
14
+ end
17
15
 
18
- def self.exist?(pathname = default_pathname)
19
- File.exist?(pathname)
20
- end
16
+ def self.exist?(pathname = default_pathname)
17
+ File.exist?(pathname)
18
+ end
21
19
 
22
- def initialize(pathname = self.class.default_pathname)
23
- @pathname = pathname
24
- if File.directory?(path)
25
- Imap::Backup::Utils.check_permissions path, 0700
26
- end
27
- if File.exist?(@pathname)
28
- Imap::Backup::Utils.check_permissions @pathname, 0600
29
- @data = JSON.parse(File.read(@pathname), :symbolize_names => true)
30
- else
31
- @data = {:accounts => []}
32
- end
33
- end
20
+ def initialize(pathname = self.class.default_pathname)
21
+ @pathname = pathname
22
+ if File.directory?(path)
23
+ Imap::Backup::Utils.check_permissions path, 0700
24
+ end
25
+ if File.exist?(@pathname)
26
+ Imap::Backup::Utils.check_permissions @pathname, 0600
27
+ @data = JSON.parse(File.read(@pathname), :symbolize_names => true)
28
+ else
29
+ @data = {:accounts => []}
30
+ end
31
+ end
34
32
 
35
- def save
36
- mkdir_private path
37
- File.open(@pathname, 'w') { |f| f.write(JSON.pretty_generate(@data)) }
38
- FileUtils.chmod 0600, @pathname
39
- @data[:accounts].each do |account|
40
- mkdir_private account[:local_path]
41
- account[:folders].each do |f|
42
- parts = f[:name].split('/')
43
- p = account[:local_path].clone
44
- parts.each do |part|
45
- p = File.join(p, part)
46
- mkdir_private p
47
- end
48
- end
33
+ def save
34
+ mkdir_private path
35
+ File.open(@pathname, 'w') { |f| f.write(JSON.pretty_generate(@data)) }
36
+ FileUtils.chmod 0600, @pathname
37
+ @data[:accounts].each do |account|
38
+ mkdir_private account[:local_path]
39
+ account[:folders].each do |f|
40
+ parts = f[:name].split('/')
41
+ p = account[:local_path].clone
42
+ parts.each do |part|
43
+ p = File.join(p, part)
44
+ mkdir_private p
49
45
  end
50
46
  end
47
+ end
48
+ end
51
49
 
52
- def path
53
- File.dirname(@pathname)
54
- end
50
+ def path
51
+ File.dirname(@pathname)
52
+ end
55
53
 
56
- private
54
+ private
57
55
 
58
- def mkdir_private(path)
59
- if ! File.directory?(path)
60
- FileUtils.mkdir path
61
- end
62
- if Imap::Backup::Utils::stat(path) != 0700
63
- FileUtils.chmod 0700, path
64
- end
65
- end
56
+ def mkdir_private(path)
57
+ if ! File.directory?(path)
58
+ FileUtils.mkdir path
59
+ end
60
+ if Imap::Backup::Utils::stat(path) != 0700
61
+ FileUtils.chmod 0700, path
66
62
  end
67
63
  end
68
64
  end
69
65
  end
70
-