imap-backup 9.1.0 → 9.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e9d95502af3aa99d3ad49581ff743c641d12f308a1326ba2aabc1dcc2ec5f4f
4
- data.tar.gz: ddf93a5e5bcc90ef698607b53224f5082da7cd0a7f65b52e0bf892999bb96898
3
+ metadata.gz: 2817e61358b848f7dbef08e1a16562def8cd364e66d317e4dac56c1f5e62f958
4
+ data.tar.gz: ec0e2d2963e863b204b0529ca3746492703486e8f77a9e7c08bc301b203249de
5
5
  SHA512:
6
- metadata.gz: 582736b8992988cb3d34c48022cf59044d92c8c9488a133afe49610f4abf8853a98c31eb6c61e677d47363252dcbf5a2b923646b2643dd059bd71923a06e652f
7
- data.tar.gz: 11ba0236028272763b078aa0e9d84d636fcb98478a7d225c1c8406c771838d158fd218ba259697a2aac7ead306d9fe13eb89f2aec1712d7416ff7afca86beb4e
6
+ metadata.gz: 66871fce3faebbcbd87737fef230803b46f32025b28753fe4f83813e652ef14817fce302da0570000f0d0ecb582862589a84f535a94aa1fa7cc1578eaf30591c
7
+ data.tar.gz: 274cfc47767322e31eb1e7206c3d1d449b2098ba1a65073c80aa5010c06924abfc7a952aeace01436715a7f95599503d86bcecbbdf210f7c8b5529bf7bee4fdf
@@ -54,8 +54,8 @@ module Imap::Backup
54
54
  aliases: ["-r"]
55
55
  )
56
56
  def backup
57
- Imap::Backup::Logger.setup_logging options
58
- Backup.new(options).run
57
+ non_logging_options = Imap::Backup::Logger.setup_logging(options)
58
+ Backup.new(non_logging_options).run
59
59
  end
60
60
 
61
61
  desc "local SUBCOMMAND [OPTIONS]", "View local info"
@@ -111,8 +111,8 @@ module Imap::Backup
111
111
  aliases: ["-s"]
112
112
  )
113
113
  def migrate(source_email, destination_email)
114
- Imap::Backup::Logger.setup_logging options
115
- Migrate.new(source_email, destination_email, **options).run
114
+ non_logging_options = Imap::Backup::Logger.setup_logging(options)
115
+ Migrate.new(source_email, destination_email, **non_logging_options).run
116
116
  end
117
117
 
118
118
  desc(
@@ -161,8 +161,8 @@ module Imap::Backup
161
161
  aliases: ["-s"]
162
162
  )
163
163
  def mirror(source_email, destination_email)
164
- Imap::Backup::Logger.setup_logging options
165
- Mirror.new(source_email, destination_email, **options).run
164
+ non_logging_options = Imap::Backup::Logger.setup_logging(options)
165
+ Mirror.new(source_email, destination_email, **non_logging_options).run
166
166
  end
167
167
 
168
168
  desc "remote SUBCOMMAND [OPTIONS]", "View info about online accounts"
@@ -178,8 +178,8 @@ module Imap::Backup
178
178
  quiet_option
179
179
  verbose_option
180
180
  def restore(email = nil)
181
- Imap::Backup::Logger.setup_logging options
182
- Restore.new(email, options).run
181
+ non_logging_options = Imap::Backup::Logger.setup_logging(options)
182
+ Restore.new(email, non_logging_options).run
183
183
  end
184
184
 
185
185
  desc "setup", "Configure imap-backup"
@@ -191,8 +191,8 @@ module Imap::Backup
191
191
  quiet_option
192
192
  verbose_option
193
193
  def setup
194
- Imap::Backup::Logger.setup_logging options
195
- Setup.new(options).run
194
+ non_logging_options = Imap::Backup::Logger.setup_logging(options)
195
+ Setup.new(non_logging_options).run
196
196
  end
197
197
 
198
198
  desc "stats EMAIL [OPTIONS]", "Print stats for each account folder"
@@ -206,8 +206,8 @@ module Imap::Backup
206
206
  quiet_option
207
207
  verbose_option
208
208
  def stats(email)
209
- Imap::Backup::Logger.setup_logging options
210
- Stats.new(email, options).run
209
+ non_logging_options = Imap::Backup::Logger.setup_logging(options)
210
+ Stats.new(email, non_logging_options).run
211
211
  end
212
212
 
213
213
  desc "utils SUBCOMMAND [OPTIONS]", "Various utilities"
@@ -2,7 +2,7 @@ require "logger"
2
2
  require "singleton"
3
3
 
4
4
  require "imap/backup/configuration"
5
- require "imap/backup/sanitizer"
5
+ require "text/sanitizer"
6
6
 
7
7
  module Imap::Backup
8
8
  class Logger
@@ -13,11 +13,14 @@ module Imap::Backup
13
13
  end
14
14
 
15
15
  def self.setup_logging(options = {})
16
+ copy = options.clone
17
+ quiet = copy.delete(:quiet)
18
+ verbose = copy.delete(:verbose)
16
19
  level =
17
20
  case
18
- when options[:quiet]
21
+ when quiet
19
22
  ::Logger::Severity::UNKNOWN
20
- when options[:verbose]
23
+ when verbose
21
24
  ::Logger::Severity::DEBUG
22
25
  else
23
26
  ::Logger::Severity::INFO
@@ -25,10 +28,12 @@ module Imap::Backup
25
28
  logger.level = level
26
29
  debug = level == ::Logger::Severity::DEBUG
27
30
  Net::IMAP.debug = debug
31
+
32
+ copy
28
33
  end
29
34
 
30
35
  def self.sanitize_stderr
31
- sanitizer = Sanitizer.new($stdout)
36
+ sanitizer = Text::Sanitizer.new($stdout)
32
37
  previous_stderr = $stderr
33
38
  $stderr = sanitizer
34
39
  yield
@@ -0,0 +1,25 @@
1
+ module Imap::Backup
2
+ class Naming
3
+ INVALID_FILENAME_CHARACTERS = ":%;".freeze
4
+ INVALID_FILENAME_CHARACTER_MATCH = /([#{INVALID_FILENAME_CHARACTERS}])/.freeze
5
+
6
+ # `*_path` functions treat `/` as an acceptable character
7
+ def self.to_local_path(name)
8
+ name.gsub(INVALID_FILENAME_CHARACTER_MATCH) do |character|
9
+ hex =
10
+ character.
11
+ codepoints[0].
12
+ to_s(16)
13
+ "%#{hex};"
14
+ end
15
+ end
16
+
17
+ def self.from_local_path(name)
18
+ name.gsub(/%(.*?);/) do
19
+ ::Regexp.last_match(1).
20
+ to_i(16).
21
+ chr("UTF-8")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,4 +1,6 @@
1
1
  module Imap::Backup
2
+ class Serializer; end
3
+
2
4
  class Serializer::Appender
3
5
  attr_reader :imap
4
6
  attr_reader :folder
@@ -1,6 +1,7 @@
1
1
  require "forwardable"
2
2
 
3
3
  require "email/mboxrd/message"
4
+ require "imap/backup/naming"
4
5
  require "imap/backup/serializer/appender"
5
6
  require "imap/backup/serializer/imap"
6
7
  require "imap/backup/serializer/message"
@@ -72,7 +73,7 @@ module Imap::Backup
72
73
  def append(uid, message, flags)
73
74
  validate!
74
75
 
75
- appender = Serializer::Appender.new(folder: folder, imap: imap, mbox: mbox)
76
+ appender = Serializer::Appender.new(folder: sanitized, imap: imap, mbox: mbox)
76
77
  appender.run(uid: uid, message: message, flags: flags)
77
78
  end
78
79
 
@@ -116,14 +117,16 @@ module Imap::Backup
116
117
  end
117
118
 
118
119
  def folder_path
119
- self.class.folder_path_for(path: path, folder: folder)
120
+ self.class.folder_path_for(path: path, folder: sanitized)
120
121
  end
121
122
 
122
123
  private
123
124
 
124
125
  def rename(new_name)
125
126
  destination = self.class.folder_path_for(path: path, folder: new_name)
126
- ensure_containing_directory(new_name)
127
+ relative = File.dirname(new_name)
128
+ directory = Serializer::Directory.new(path, relative)
129
+ directory.ensure_exists
127
130
  mbox.rename destination
128
131
  imap.rename destination
129
132
  end
@@ -136,7 +139,7 @@ module Imap::Backup
136
139
  def mbox
137
140
  @mbox ||=
138
141
  begin
139
- ensure_containing_directory(folder)
142
+ ensure_containing_directory
140
143
  Serializer::Mbox.new(folder_path)
141
144
  end
142
145
  end
@@ -144,11 +147,15 @@ module Imap::Backup
144
147
  def imap
145
148
  @imap ||=
146
149
  begin
147
- ensure_containing_directory(folder)
150
+ ensure_containing_directory
148
151
  Serializer::Imap.new(folder_path)
149
152
  end
150
153
  end
151
154
 
155
+ def sanitized
156
+ @sanitized ||= Naming.to_local_path(folder)
157
+ end
158
+
152
159
  def optionally_migrate2to3
153
160
  migrator = Version2Migrator.new(folder_path)
154
161
  return if !migrator.required?
@@ -162,8 +169,8 @@ module Imap::Backup
162
169
  migrator.run
163
170
  end
164
171
 
165
- def ensure_containing_directory(folder)
166
- relative = File.dirname(folder)
172
+ def ensure_containing_directory
173
+ relative = File.dirname(sanitized)
167
174
  directory = Serializer::Directory.new(path, relative)
168
175
  directory.ensure_exists
169
176
  end
@@ -2,7 +2,7 @@ module Imap; end
2
2
 
3
3
  module Imap::Backup
4
4
  MAJOR = 9
5
- MINOR = 1
5
+ MINOR = 2
6
6
  REVISION = 0
7
7
  PRE = nil
8
8
  VERSION = [MAJOR, MINOR, REVISION, PRE].compact.map(&:to_s).join(".")
@@ -0,0 +1,46 @@
1
+ require "forwardable"
2
+
3
+ module Text; end
4
+
5
+ class Text::Sanitizer
6
+ extend Forwardable
7
+
8
+ attr_reader :output
9
+
10
+ delegate puts: :output
11
+ delegate write: :output
12
+
13
+ def initialize(output)
14
+ @output = output
15
+ @current = ""
16
+ end
17
+
18
+ def print(*args)
19
+ @current << args.join
20
+ loop do
21
+ line, newline, rest = @current.partition("\n")
22
+ break if newline != "\n"
23
+
24
+ clean = sanitize(line)
25
+ output.puts clean
26
+ @current = rest
27
+ end
28
+ end
29
+
30
+ def flush
31
+ return if @current == ""
32
+
33
+ clean = sanitize(@current)
34
+ output.puts clean
35
+ end
36
+
37
+ private
38
+
39
+ def sanitize(text)
40
+ # Hide password in Net::IMAP debug output
41
+ text.gsub(
42
+ /\A(C: RUBY\d+ LOGIN \S+) \S+/,
43
+ "\\1 [PASSWORD REDACTED]"
44
+ )
45
+ end
46
+ 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: 9.1.0
4
+ version: 9.2.0
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-02-18 00:00:00.000000000 Z
11
+ date: 2023-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -258,7 +258,7 @@ files:
258
258
  - lib/imap/backup/migrator.rb
259
259
  - lib/imap/backup/mirror.rb
260
260
  - lib/imap/backup/mirror/map.rb
261
- - lib/imap/backup/sanitizer.rb
261
+ - lib/imap/backup/naming.rb
262
262
  - lib/imap/backup/serializer.rb
263
263
  - lib/imap/backup/serializer/appender.rb
264
264
  - lib/imap/backup/serializer/directory.rb
@@ -282,6 +282,7 @@ files:
282
282
  - lib/imap/backup/utils.rb
283
283
  - lib/imap/backup/version.rb
284
284
  - lib/retry_on_error.rb
285
+ - lib/text/sanitizer.rb
285
286
  homepage: https://github.com/joeyates/imap-backup
286
287
  licenses:
287
288
  - MIT
@@ -1,46 +0,0 @@
1
- require "forwardable"
2
-
3
- module Imap::Backup
4
- class Sanitizer
5
- extend Forwardable
6
-
7
- attr_reader :output
8
-
9
- delegate puts: :output
10
- delegate write: :output
11
-
12
- def initialize(output)
13
- @output = output
14
- @current = ""
15
- end
16
-
17
- def print(*args)
18
- @current << args.join
19
- loop do
20
- line, newline, rest = @current.partition("\n")
21
- break if newline != "\n"
22
-
23
- clean = sanitize(line)
24
- output.puts clean
25
- @current = rest
26
- end
27
- end
28
-
29
- def flush
30
- return if @current == ""
31
-
32
- clean = sanitize(@current)
33
- output.puts clean
34
- end
35
-
36
- private
37
-
38
- def sanitize(text)
39
- # Hide password in Net::IMAP debug output
40
- text.gsub(
41
- /\A(C: RUBY\d+ LOGIN \S+) \S+/,
42
- "\\1 [PASSWORD REDACTED]"
43
- )
44
- end
45
- end
46
- end