imap-backup 6.0.0.rc2 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/imap-backup.gemspec +5 -1
  3. data/lib/cli_coverage.rb +11 -11
  4. data/lib/email/provider/apple_mail.rb +4 -0
  5. data/lib/email/provider/base.rb +6 -0
  6. data/lib/email/provider/purelymail.rb +11 -0
  7. data/lib/email/provider/unknown.rb +2 -0
  8. data/lib/email/provider.rb +5 -0
  9. data/lib/imap/backup/account/connection/backup_folders.rb +27 -0
  10. data/lib/imap/backup/account/connection/client_factory.rb +55 -0
  11. data/lib/imap/backup/account/connection/folder_names.rb +26 -0
  12. data/lib/imap/backup/account/connection.rb +16 -96
  13. data/lib/imap/backup/account/folder.rb +31 -9
  14. data/lib/imap/backup/account.rb +15 -6
  15. data/lib/imap/backup/cli/backup.rb +1 -3
  16. data/lib/imap/backup/cli/helpers.rb +24 -22
  17. data/lib/imap/backup/cli/local.rb +20 -13
  18. data/lib/imap/backup/cli/migrate.rb +4 -10
  19. data/lib/imap/backup/cli/restore.rb +8 -7
  20. data/lib/imap/backup/cli/setup.rb +10 -8
  21. data/lib/imap/backup/cli/stats.rb +78 -0
  22. data/lib/imap/backup/cli/status.rb +2 -2
  23. data/lib/imap/backup/cli/utils.rb +4 -6
  24. data/lib/imap/backup/cli.rb +24 -3
  25. data/lib/imap/backup/configuration.rb +9 -11
  26. data/lib/imap/backup/downloader.rb +75 -31
  27. data/lib/imap/backup/migrator.rb +5 -5
  28. data/lib/imap/backup/sanitizer.rb +3 -2
  29. data/lib/imap/backup/serializer/appender.rb +49 -0
  30. data/lib/imap/backup/serializer/imap.rb +27 -3
  31. data/lib/imap/backup/serializer/mbox.rb +18 -2
  32. data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
  33. data/lib/imap/backup/serializer/unused_name_finder.rb +25 -0
  34. data/lib/imap/backup/serializer.rb +64 -84
  35. data/lib/imap/backup/setup/account/header.rb +81 -0
  36. data/lib/imap/backup/setup/account.rb +28 -91
  37. data/lib/imap/backup/setup/asker.rb +4 -15
  38. data/lib/imap/backup/setup/backup_path.rb +45 -0
  39. data/lib/imap/backup/setup/email.rb +45 -0
  40. data/lib/imap/backup/setup/folder_chooser.rb +3 -3
  41. data/lib/imap/backup/setup/helpers.rb +1 -1
  42. data/lib/imap/backup/setup.rb +7 -6
  43. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +39 -20
  44. data/lib/imap/backup/uploader.rb +46 -8
  45. data/lib/imap/backup/utils.rb +1 -1
  46. data/lib/imap/backup/version.rb +2 -2
  47. data/lib/imap/backup.rb +0 -1
  48. metadata +32 -134
  49. data/spec/features/backup_spec.rb +0 -100
  50. data/spec/features/configuration/minimal_configuration.rb +0 -15
  51. data/spec/features/configuration/missing_configuration.rb +0 -14
  52. data/spec/features/folders_spec.rb +0 -36
  53. data/spec/features/helper.rb +0 -2
  54. data/spec/features/local/list_accounts_spec.rb +0 -12
  55. data/spec/features/local/list_emails_spec.rb +0 -21
  56. data/spec/features/local/list_folders_spec.rb +0 -21
  57. data/spec/features/local/show_an_email_spec.rb +0 -34
  58. data/spec/features/migrate_spec.rb +0 -35
  59. data/spec/features/remote/list_account_folders_spec.rb +0 -16
  60. data/spec/features/restore_spec.rb +0 -162
  61. data/spec/features/status_spec.rb +0 -43
  62. data/spec/features/support/aruba.rb +0 -78
  63. data/spec/features/support/backup_directory.rb +0 -43
  64. data/spec/features/support/email_server.rb +0 -110
  65. data/spec/features/support/shared/connection_context.rb +0 -14
  66. data/spec/features/support/shared/message_fixtures.rb +0 -16
  67. data/spec/fixtures/connection.yml +0 -7
  68. data/spec/spec_helper.rb +0 -15
  69. data/spec/support/fixtures.rb +0 -11
  70. data/spec/support/higline_test_helpers.rb +0 -8
  71. data/spec/support/silence_logging.rb +0 -7
  72. data/spec/unit/email/mboxrd/message_spec.rb +0 -177
  73. data/spec/unit/email/provider/apple_mail_spec.rb +0 -7
  74. data/spec/unit/email/provider/base_spec.rb +0 -11
  75. data/spec/unit/email/provider/fastmail_spec.rb +0 -7
  76. data/spec/unit/email/provider/gmail_spec.rb +0 -7
  77. data/spec/unit/email/provider_spec.rb +0 -27
  78. data/spec/unit/imap/backup/account/connection_spec.rb +0 -433
  79. data/spec/unit/imap/backup/account/folder_spec.rb +0 -261
  80. data/spec/unit/imap/backup/account_spec.rb +0 -246
  81. data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -58
  82. data/spec/unit/imap/backup/cli/backup_spec.rb +0 -19
  83. data/spec/unit/imap/backup/cli/folders_spec.rb +0 -39
  84. data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
  85. data/spec/unit/imap/backup/cli/local_spec.rb +0 -100
  86. data/spec/unit/imap/backup/cli/migrate_spec.rb +0 -80
  87. data/spec/unit/imap/backup/cli/restore_spec.rb +0 -67
  88. data/spec/unit/imap/backup/cli/setup_spec.rb +0 -17
  89. data/spec/unit/imap/backup/cli/utils_spec.rb +0 -125
  90. data/spec/unit/imap/backup/cli_spec.rb +0 -93
  91. data/spec/unit/imap/backup/client/apple_mail_spec.rb +0 -9
  92. data/spec/unit/imap/backup/client/default_spec.rb +0 -22
  93. data/spec/unit/imap/backup/configuration_spec.rb +0 -238
  94. data/spec/unit/imap/backup/downloader_spec.rb +0 -96
  95. data/spec/unit/imap/backup/logger_spec.rb +0 -48
  96. data/spec/unit/imap/backup/migrator_spec.rb +0 -58
  97. data/spec/unit/imap/backup/sanitizer_spec.rb +0 -42
  98. data/spec/unit/imap/backup/serializer/directory_spec.rb +0 -37
  99. data/spec/unit/imap/backup/serializer/imap_spec.rb +0 -218
  100. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +0 -45
  101. data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -101
  102. data/spec/unit/imap/backup/serializer_spec.rb +0 -296
  103. data/spec/unit/imap/backup/setup/account_spec.rb +0 -461
  104. data/spec/unit/imap/backup/setup/asker_spec.rb +0 -137
  105. data/spec/unit/imap/backup/setup/connection_tester_spec.rb +0 -51
  106. data/spec/unit/imap/backup/setup/folder_chooser_spec.rb +0 -146
  107. data/spec/unit/imap/backup/setup/helpers_spec.rb +0 -15
  108. data/spec/unit/imap/backup/setup_spec.rb +0 -301
  109. data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +0 -116
  110. data/spec/unit/imap/backup/uploader_spec.rb +0 -54
  111. data/spec/unit/imap/backup/utils_spec.rb +0 -92
  112. data/spec/unit/retry_on_error_spec.rb +0 -34
@@ -6,14 +6,20 @@ module Imap::Backup
6
6
  @folder_path = folder_path
7
7
  end
8
8
 
9
+ def valid?
10
+ exist?
11
+ end
12
+
9
13
  def append(message)
10
14
  File.open(pathname, "ab") do |file|
11
15
  file.write message
12
16
  end
13
17
  end
14
18
 
15
- def exist?
16
- File.exist?(pathname)
19
+ def delete
20
+ return if !exist?
21
+
22
+ File.unlink(pathname)
17
23
  end
18
24
 
19
25
  def length
@@ -41,5 +47,15 @@ module Imap::Backup
41
47
  f.truncate(length)
42
48
  end
43
49
  end
50
+
51
+ def touch
52
+ File.open(pathname, "a") {}
53
+ end
54
+
55
+ private
56
+
57
+ def exist?
58
+ File.exist?(pathname)
59
+ end
44
60
  end
45
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,12 +1,20 @@
1
1
  require "forwardable"
2
2
 
3
3
  require "email/mboxrd/message"
4
+ require "imap/backup/serializer/appender"
4
5
  require "imap/backup/serializer/imap"
5
6
  require "imap/backup/serializer/mbox"
6
7
  require "imap/backup/serializer/mbox_enumerator"
8
+ require "imap/backup/serializer/message_enumerator"
9
+ require "imap/backup/serializer/unused_name_finder"
7
10
 
8
11
  module Imap::Backup
9
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
+
10
18
  extend Forwardable
11
19
 
12
20
  def_delegator :mbox, :pathname, :mbox_pathname
@@ -20,10 +28,25 @@ module Imap::Backup
20
28
  @folder = folder
21
29
  end
22
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
+
23
44
  def apply_uid_validity(value)
45
+ validate!
46
+
24
47
  case
25
48
  when uid_validity.nil?
26
- imap.uid_validity = value
49
+ internal_force_uid_validity(value)
27
50
  nil
28
51
  when uid_validity == value
29
52
  # NOOP
@@ -34,94 +57,71 @@ module Imap::Backup
34
57
  end
35
58
 
36
59
  def force_uid_validity(value)
37
- imap.uid_validity = value
60
+ validate!
61
+
62
+ internal_force_uid_validity(value)
38
63
  end
39
64
 
40
65
  def append(uid, message)
41
- raise "Can't add messages without uid_validity" if !imap.uid_validity
42
-
43
- uid = uid.to_i
44
- if imap.include?(uid)
45
- Logger.logger.debug(
46
- "[#{folder}] message #{uid} already downloaded - skipping"
47
- )
48
- return
49
- end
66
+ validate!
50
67
 
51
- do_append uid, message
68
+ appender = Serializer::Appender.new(folder: folder, imap: imap, mbox: mbox)
69
+ appender.run(uid: uid, message: message)
52
70
  end
53
71
 
54
72
  def load(uid_maybe_string)
73
+ validate!
74
+
55
75
  uid = uid_maybe_string.to_i
56
76
  message_index = imap.index(uid)
57
77
  return nil if message_index.nil?
58
78
 
59
- load_nth(message_index)
79
+ internal_load_nth(message_index)
60
80
  end
61
81
 
62
82
  def load_nth(index)
63
- enumerator = Serializer::MboxEnumerator.new(mbox.pathname)
64
- enumerator.each.with_index do |raw, i|
65
- next if i != index
83
+ validate!
66
84
 
67
- return Email::Mboxrd::Message.from_serialized(raw)
68
- end
69
- nil
85
+ internal_load_nth(index)
70
86
  end
71
87
 
72
- def each_message(required_uids)
73
- return enum_for(:each_message, required_uids) if !block_given?
88
+ def each_message(required_uids, &block)
89
+ validate!
74
90
 
75
- indexes = required_uids.each.with_object({}) do |uid_maybe_string, acc|
76
- uid = uid_maybe_string.to_i
77
- index = imap.index(uid)
78
- acc[index] = uid if index
79
- end
80
- enumerator = Serializer::MboxEnumerator.new(mbox.pathname)
81
- enumerator.each.with_index do |raw, i|
82
- uid = indexes[i]
83
- next if !uid
91
+ return enum_for(:each_message, required_uids) if !block
84
92
 
85
- yield uid, Email::Mboxrd::Message.from_serialized(raw)
86
- end
93
+ enumerator = Serializer::MessageEnumerator.new(imap: imap, mbox: mbox)
94
+ enumerator.run(uids: required_uids, &block)
87
95
  end
88
96
 
97
+ private
98
+
89
99
  def rename(new_name)
90
- # Initialize so we get memoized instances with the correct folder_path
91
- mbox
92
- imap
93
- @folder = new_name
94
- ensure_containing_directory
95
- mbox.rename folder_path
96
- imap.rename folder_path
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
97
104
  end
98
105
 
99
- private
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
100
115
 
101
- def do_append(uid, message)
102
- mboxrd_message = Email::Mboxrd::Message.new(message)
103
- initial = mbox.length || 0
104
- mbox_appended = false
105
- begin
106
- mbox.append mboxrd_message.to_serialized
107
- mbox_appended = true
108
- imap.append uid
109
- rescue StandardError => e
110
- mbox.rewind(initial) if mbox_appended
111
-
112
- message = <<-ERROR.gsub(/^\s*/m, "")
113
- [#{folder}] failed to append message #{uid}:
114
- #{message}. #{e}:
115
- #{e.backtrace.join("\n")}"
116
- ERROR
117
- Logger.logger.warn message
116
+ return Email::Mboxrd::Message.from_serialized(raw)
118
117
  end
118
+ nil
119
119
  end
120
120
 
121
121
  def mbox
122
122
  @mbox ||=
123
123
  begin
124
- ensure_containing_directory
124
+ ensure_containing_directory(folder)
125
125
  Serializer::Mbox.new(folder_path)
126
126
  end
127
127
  end
@@ -129,21 +129,16 @@ module Imap::Backup
129
129
  def imap
130
130
  @imap ||=
131
131
  begin
132
- ensure_containing_directory
132
+ ensure_containing_directory(folder)
133
133
  Serializer::Imap.new(folder_path)
134
134
  end
135
135
  end
136
136
 
137
137
  def folder_path
138
- folder_path_for(path, folder)
138
+ self.class.folder_path_for(path: path, folder: folder)
139
139
  end
140
140
 
141
- def folder_path_for(path, folder)
142
- relative = File.join(path, folder)
143
- File.expand_path(relative)
144
- end
145
-
146
- def ensure_containing_directory
141
+ def ensure_containing_directory(folder)
147
142
  relative = File.dirname(folder)
148
143
  directory = Serializer::Directory.new(path, relative)
149
144
  directory.ensure_exists
@@ -154,29 +149,14 @@ module Imap::Backup
154
149
  # Clear memoization so we get empty data
155
150
  @mbox = nil
156
151
  @imap = nil
157
- imap.uid_validity = value
152
+ internal_force_uid_validity(value)
158
153
 
159
154
  new_name
160
155
  end
161
156
 
162
157
  def rename_existing_folder
163
- digit = 0
164
- new_name = nil
165
- loop do
166
- extra = digit.zero? ? "" : "-#{digit}"
167
- new_name = "#{folder}-#{imap.uid_validity}#{extra}"
168
- new_folder_path = folder_path_for(path, new_name)
169
- test_mbox = Serializer::Mbox.new(new_folder_path)
170
- test_imap = Serializer::Imap.new(new_folder_path)
171
- break if !test_mbox.exist? && !test_imap.exist?
172
-
173
- digit += 1
174
- end
175
-
176
- previous = folder
177
- rename(new_name)
178
- @folder = previous
179
-
158
+ new_name = Serializer::UnusedNameFinder.new(serializer: self).run
159
+ rename new_name
180
160
  new_name
181
161
  end
182
162
  end
@@ -0,0 +1,81 @@
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}#{reset_seen_flags_after_fetch}
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 reset_seen_flags_after_fetch
57
+ return nil if !account.reset_seen_flags_after_fetch
58
+
59
+ "\nchanges to unread flags will be reset during download"
60
+ end
61
+
62
+ def space
63
+ account.connection_options ? " " * 12 : " " * 4
64
+ end
65
+
66
+ def masked_password
67
+ if (account.password == "") || account.password.nil?
68
+ "(unset)"
69
+ else
70
+ account.password.gsub(/./, "x")
71
+ end
72
+ end
73
+
74
+ def local_path
75
+ # In order to handle backslashes, as Highline effectively
76
+ # does an eval (!) on its templates, we need to doubly
77
+ # escape them
78
+ account.local_path.gsub("\\", "\\\\\\\\")
79
+ end
80
+ end
81
+ end
@@ -1,11 +1,19 @@
1
- require "imap/backup/setup/helpers"
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 = Struct.new(:config, :account, :highline) do
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
- super
14
+ @account = account
15
+ @config = config
16
+ @highline = highline
9
17
  end
10
18
 
11
19
  def run
@@ -29,6 +37,7 @@ module Imap::Backup
29
37
  modify_multi_fetch_size menu
30
38
  modify_server menu
31
39
  modify_connection_options menu
40
+ toggle_reset_seen_flags_after_fetch menu
32
41
  test_connection menu
33
42
  delete_account menu
34
43
  menu.choice("(q) return to main menu") { throw :done }
@@ -37,54 +46,12 @@ module Imap::Backup
37
46
  end
38
47
 
39
48
  def header(menu)
40
- modified = account.modified? ? "*" : ""
41
-
42
- if account.multi_fetch_size > 1
43
- multi_fetch_size = "\nmulti-fetch #{account.multi_fetch_size}"
44
- end
45
-
46
- if account.connection_options
47
- escaped =
48
- JSON.generate(account.connection_options)
49
- connection_options =
50
- "\nconnection options '#{escaped}'"
51
- space = " " * 12
52
- else
53
- connection_options = nil
54
- space = " " * 4
55
- end
56
-
57
- menu.header = <<~HEADER.chomp
58
- #{helpers.title_prefix} Account#{modified}
59
-
60
- email #{space}#{account.username}
61
- password#{space}#{masked_password}
62
- path #{space}#{account.local_path}
63
- folders #{space}#{folders.map { |f| f[:name] }.join(', ')}#{multi_fetch_size}
64
- server #{space}#{account.server}#{connection_options}
65
-
66
- Choose an action
67
- HEADER
49
+ Setup::Account::Header.new(menu: menu, account: account).run
68
50
  end
69
51
 
70
52
  def modify_email(menu)
71
53
  menu.choice("modify email") do
72
- username = Setup::Asker.email(username)
73
- Kernel.puts "username: #{username}"
74
- other_accounts = config.accounts.reject { |a| a == account }
75
- others = other_accounts.map { |a| a.username }
76
- Kernel.puts "others: #{others.inspect}"
77
- if others.include?(username)
78
- Kernel.puts(
79
- "There is already an account set up with that email address"
80
- )
81
- else
82
- account.username = username
83
- default = default_server(username)
84
- if default && (account.server.nil? || (account.server == ""))
85
- account.server = default
86
- end
87
- end
54
+ Setup::Email.new(account: account, config: config).run
88
55
  end
89
56
  end
90
57
 
@@ -96,25 +63,9 @@ module Imap::Backup
96
63
  end
97
64
  end
98
65
 
99
- def path_modification_validator(path)
100
- same = config.accounts.find do |a|
101
- a.username != account.username && a.local_path == path
102
- end
103
- if same
104
- Kernel.puts "The path '#{path}' is used to backup " \
105
- "the account '#{same.username}'"
106
- false
107
- else
108
- true
109
- end
110
- end
111
-
112
66
  def modify_backup_path(menu)
113
67
  menu.choice("modify backup path") do
114
- existing = account.local_path.clone
115
- account.local_path = Setup::Asker.backup_path(
116
- account.local_path, ->(path) { path_modification_validator(path) }
117
- )
68
+ Setup::BackupPath.new(account: account, config: config).run
118
69
  end
119
70
  end
120
71
 
@@ -153,6 +104,19 @@ module Imap::Backup
153
104
  end
154
105
  end
155
106
 
107
+ def toggle_reset_seen_flags_after_fetch(menu)
108
+ menu_item =
109
+ if account.reset_seen_flags_after_fetch
110
+ "don't fix changes to unread flags during download"
111
+ else
112
+ "fix changes to unread flags during download"
113
+ end
114
+ new_value = account.reset_seen_flags_after_fetch ? nil : true
115
+ menu.choice(menu_item) do
116
+ account.reset_seen_flags_after_fetch = new_value
117
+ end
118
+ end
119
+
156
120
  def test_connection(menu)
157
121
  menu.choice("test connection") do
158
122
  result = Setup::ConnectionTester.new(account).test
@@ -169,32 +133,5 @@ module Imap::Backup
169
133
  end
170
134
  end
171
135
  end
172
-
173
- def folders
174
- account.folders || []
175
- end
176
-
177
- def masked_password
178
- if (account.password == "") || account.password.nil?
179
- "(unset)"
180
- else
181
- account.password.gsub(/./, "x")
182
- end
183
- end
184
-
185
- def default_server(username)
186
- provider = Email::Provider.for_address(username)
187
-
188
- if provider.is_a?(Email::Provider::Unknown)
189
- Kernel.puts "Can't decide provider for email address '#{username}'"
190
- return nil
191
- end
192
-
193
- provider.host
194
- end
195
-
196
- def helpers
197
- Setup::Helpers.new
198
- end
199
136
  end
200
137
  end
@@ -1,11 +1,13 @@
1
1
  module Imap::Backup
2
2
  class Setup; end
3
3
 
4
- Setup::Asker = Struct.new(:highline) do
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
- super
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,45 @@
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 || default
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
+ def default
23
+ File.join(config.path, account.username.tr("@", "_"))
24
+ end
25
+
26
+ private
27
+
28
+ def highline
29
+ Setup.highline
30
+ end
31
+
32
+ def path_modification_validator(path)
33
+ same = config.accounts.find do |a|
34
+ a.username != account.username && a.local_path == path
35
+ end
36
+ if same
37
+ Kernel.puts "The path '#{path}' is used to backup " \
38
+ "the account '#{same.username}'"
39
+ false
40
+ else
41
+ true
42
+ end
43
+ end
44
+ end
45
+ 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