imap-backup 9.1.0 → 9.2.0

Sign up to get free protection for your applications and to get access to all the features.
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