imap-backup 16.6.0 → 17.0.0.rc0
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/docs/TODO.md +21 -0
- data/lib/imap/backup/email/mboxrd/message.rb +17 -2
- data/lib/imap/backup/serializer/imap.rb +44 -6
- data/lib/imap/backup/version.rb +3 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4b4c01b65abcd4b7fe7f57d214ce3d0f141085058c3aac3245842bac7dc3bda3
|
|
4
|
+
data.tar.gz: 418df48403a0e2d28e63b4ab233d69de327e3e139b975ceac8056eb972d05eba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a31419c312cfcfe21bf8dcb36a9093827dd1c3f9a6d4bec599c8fd53a7e426801bf1f9c014c734a73334321e1ecb1973cdac18f5410a9330021c72473df4821
|
|
7
|
+
data.tar.gz: 81c4d68861e9b77ef064897834e9631b682d576e25ca4fb7625afb15b87dc11ba729bb27940edaefb8bc65a8a88f614ae11129171c8ced9a2d8ad03f122fcb5d
|
data/docs/TODO.md
CHANGED
|
@@ -33,3 +33,24 @@ Currently, only the Download Strategy Chooser screen has localized help function
|
|
|
33
33
|
- Other setup screens (folder chooser, backup path, etc.)
|
|
34
34
|
- Add translation keys for help text to locale files (`lib/imap/backup/locales/en.yml` and `lib/imap/backup/locales/it.yml`)
|
|
35
35
|
- Follow the pattern: menu choice for "help" that displays localized help text and waits for key press
|
|
36
|
+
|
|
37
|
+
# Fix mboxrd Quote Serialization Bug
|
|
38
|
+
|
|
39
|
+
Status: [x]
|
|
40
|
+
|
|
41
|
+
## Description
|
|
42
|
+
|
|
43
|
+
The `add_extra_quote` method in `Email::Mboxrd::Message` incorrectly quotes all lines beginning with `From` (e.g. `From:` headers), rather than only lines beginning with `From ` (with a trailing space). The corresponding `clean_serialized` method has the same problem on load. This results in mbox files storing corrupted content. The fix involves correcting both regexes, bumping the metadata format version, and migrating existing files on load.
|
|
44
|
+
|
|
45
|
+
## Technical Specifics
|
|
46
|
+
|
|
47
|
+
- In [lib/imap/backup/serializer/imap.rb](lib/imap/backup/serializer/imap.rb):
|
|
48
|
+
- Bump `CURRENT_VERSION` from `3` to `3.1`
|
|
49
|
+
- Add `3` to `LOADABLE_VERSIONS`: `LOADABLE_VERSIONS = [3, 3.1].freeze`
|
|
50
|
+
- In `ensure_loaded`, use a `case data[:version]` branch:
|
|
51
|
+
- `when CURRENT_VERSION` — load messages normally
|
|
52
|
+
- `when 3` — load each message using the old (buggy) deserialization logic (`from_serialized_v3`), and set `@version = CURRENT_VERSION` so the next save writes version 3.1
|
|
53
|
+
- In [lib/imap/backup/email/mboxrd/message.rb](lib/imap/backup/email/mboxrd/message.rb):
|
|
54
|
+
- Fix `add_extra_quote`: change regex from `/\n(>*From)/` to `/\n(>*From )/`
|
|
55
|
+
- Fix `clean_serialized`: change regex from `/^>(>*From)/` to `/^>(>*From )/`
|
|
56
|
+
- Add `clean_serialized_v3` (using the old regex `/^>(>*From)/`) and a corresponding `from_serialized_v3` class method for use during migration of version 3 files
|
|
@@ -14,7 +14,7 @@ module Imap::Backup
|
|
|
14
14
|
# and with one level of '>' quoting removed from other lines
|
|
15
15
|
# that start with 'From'
|
|
16
16
|
def self.clean_serialized(serialized)
|
|
17
|
-
cleaned = serialized.gsub(/^>(>*From)/, "\\1")
|
|
17
|
+
cleaned = serialized.gsub(/^>(>*From )/, "\\1")
|
|
18
18
|
# Serialized messages in this format *should* start with a line
|
|
19
19
|
# From xxx yy zz
|
|
20
20
|
# rubocop:disable Style/IfUnlessModifier
|
|
@@ -32,6 +32,21 @@ module Imap::Backup
|
|
|
32
32
|
new(clean_serialized(serialized))
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Deserializes a message stored with the old (v3) quoting logic,
|
|
36
|
+
# which incorrectly quoted all 'From' lines, not just 'From ' lines.
|
|
37
|
+
def self.clean_serialized_v3(serialized)
|
|
38
|
+
cleaned = serialized.gsub(/^>(>*From)/, "\\1")
|
|
39
|
+
cleaned = cleaned.sub(/^From .*[\r\n]*/, "") if cleaned.start_with?("From ")
|
|
40
|
+
cleaned
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @param serialized [String] the on-disk version of a v3 message
|
|
44
|
+
#
|
|
45
|
+
# @return [Message] the original message
|
|
46
|
+
def self.from_serialized_v3(serialized)
|
|
47
|
+
new(clean_serialized_v3(serialized))
|
|
48
|
+
end
|
|
49
|
+
|
|
35
50
|
# @return [String] the original message body
|
|
36
51
|
attr_reader :supplied_body
|
|
37
52
|
|
|
@@ -110,7 +125,7 @@ module Imap::Backup
|
|
|
110
125
|
# 'From ' can be taken as the beginning of messages.
|
|
111
126
|
# http://www.digitalpreservation.gov/formats/fdd/fdd000385.shtml
|
|
112
127
|
# Here we add an extra '>' before any "From" or ">From".
|
|
113
|
-
body.gsub(/\n(>*From)/, "\n>\\1")
|
|
128
|
+
body.gsub(/\n(>*From )/, "\n>\\1")
|
|
114
129
|
end
|
|
115
130
|
|
|
116
131
|
def asctime
|
|
@@ -12,7 +12,9 @@ module Imap::Backup
|
|
|
12
12
|
# Stores message metadata
|
|
13
13
|
class Serializer::Imap
|
|
14
14
|
# The version number to store in the metadata file
|
|
15
|
-
CURRENT_VERSION = 3
|
|
15
|
+
CURRENT_VERSION = 3.1
|
|
16
|
+
|
|
17
|
+
LOADABLE_VERSIONS = [3, 3.1].freeze
|
|
16
18
|
|
|
17
19
|
# @return [Serializer::Files::Path] The path of the imap metadata file, without the '.imap'
|
|
18
20
|
# extension
|
|
@@ -41,7 +43,9 @@ module Imap::Backup
|
|
|
41
43
|
tsx.begin({savepoint: {messages: messages.dup, uid_validity: uid_validity}}) do
|
|
42
44
|
block.call
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
if tsx.data
|
|
47
|
+
save_internal(version: CURRENT_VERSION, uid_validity: uid_validity, messages: messages)
|
|
48
|
+
end
|
|
45
49
|
rescue Exception => e
|
|
46
50
|
Logger.logger.error "#{self.class} handling #{e.class}"
|
|
47
51
|
rollback
|
|
@@ -72,7 +76,7 @@ module Imap::Backup
|
|
|
72
76
|
|
|
73
77
|
def valid?
|
|
74
78
|
return false if !exist?
|
|
75
|
-
return false if version
|
|
79
|
+
return false if !loadable_version?(version)
|
|
76
80
|
return false if !uid_validity
|
|
77
81
|
|
|
78
82
|
true
|
|
@@ -208,7 +212,7 @@ module Imap::Backup
|
|
|
208
212
|
|
|
209
213
|
ensure_loaded
|
|
210
214
|
|
|
211
|
-
save_internal(version:
|
|
215
|
+
save_internal(version: CURRENT_VERSION, uid_validity: uid_validity, messages: messages)
|
|
212
216
|
end
|
|
213
217
|
|
|
214
218
|
private
|
|
@@ -232,9 +236,19 @@ module Imap::Backup
|
|
|
232
236
|
|
|
233
237
|
data = load
|
|
234
238
|
if data
|
|
235
|
-
|
|
239
|
+
case data[:version]
|
|
240
|
+
when CURRENT_VERSION
|
|
241
|
+
@messages = data[:messages].map { |m| Serializer::Message.new(mbox: mbox, **m) }
|
|
242
|
+
@version = CURRENT_VERSION
|
|
243
|
+
when 3
|
|
244
|
+
@messages = load_v3_messages(data[:messages])
|
|
245
|
+
@uid_validity = data[:uid_validity]
|
|
246
|
+
@version = CURRENT_VERSION
|
|
247
|
+
@loaded = true
|
|
248
|
+
save_internal(version: CURRENT_VERSION, uid_validity: uid_validity, messages: messages)
|
|
249
|
+
return
|
|
250
|
+
end
|
|
236
251
|
@uid_validity = data[:uid_validity]
|
|
237
|
-
@version = data[:version]
|
|
238
252
|
else
|
|
239
253
|
@messages = []
|
|
240
254
|
@uid_validity = nil
|
|
@@ -255,6 +269,7 @@ module Imap::Backup
|
|
|
255
269
|
end
|
|
256
270
|
|
|
257
271
|
return nil if !data.key?(:version)
|
|
272
|
+
return nil if !loadable_version?(data[:version])
|
|
258
273
|
return nil if !data.key?(:uid_validity)
|
|
259
274
|
return nil if !data.key?(:messages)
|
|
260
275
|
return nil if !data[:messages].is_a?(Array)
|
|
@@ -262,6 +277,29 @@ module Imap::Backup
|
|
|
262
277
|
data
|
|
263
278
|
end
|
|
264
279
|
|
|
280
|
+
def loadable_version?(version)
|
|
281
|
+
LOADABLE_VERSIONS.include?(version)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def load_v3_messages(message_data)
|
|
285
|
+
messages = []
|
|
286
|
+
offset = 0
|
|
287
|
+
new_content = +""
|
|
288
|
+
message_data.each do |m|
|
|
289
|
+
raw = mbox.read(m[:offset], m[:length])
|
|
290
|
+
original = Email::Mboxrd::Message.from_serialized_v3(raw)
|
|
291
|
+
serialized = original.to_serialized
|
|
292
|
+
messages << Serializer::Message.new(
|
|
293
|
+
mbox: mbox, uid: m[:uid], offset: offset,
|
|
294
|
+
length: serialized.bytesize, flags: m[:flags] || []
|
|
295
|
+
)
|
|
296
|
+
new_content << serialized
|
|
297
|
+
offset += serialized.bytesize
|
|
298
|
+
end
|
|
299
|
+
File.open(mbox.pathname, "wb") { |f| f.write(new_content) }
|
|
300
|
+
messages
|
|
301
|
+
end
|
|
302
|
+
|
|
265
303
|
def mbox
|
|
266
304
|
@mbox ||= Serializer::Mbox.new(files_path: files_path)
|
|
267
305
|
end
|
data/lib/imap/backup/version.rb
CHANGED
|
@@ -2,13 +2,13 @@ module Imap; end
|
|
|
2
2
|
|
|
3
3
|
module Imap::Backup
|
|
4
4
|
# @private
|
|
5
|
-
MAJOR =
|
|
5
|
+
MAJOR = 17
|
|
6
6
|
# @private
|
|
7
|
-
MINOR =
|
|
7
|
+
MINOR = 0
|
|
8
8
|
# @private
|
|
9
9
|
REVISION = 0
|
|
10
10
|
# @private
|
|
11
|
-
PRE =
|
|
11
|
+
PRE = "rc0"
|
|
12
12
|
# The application version
|
|
13
13
|
VERSION = [MAJOR, MINOR, REVISION, PRE].compact.map(&:to_s).join(".")
|
|
14
14
|
end
|