Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions lib/net/imap/command_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,12 @@ def send_data(imap, tag) = imap.__send__(:put_string, data)

class RawData < CommandData # :nodoc:
def initialize(data:)
data = split_parts(data)
case data
in String then data = self.class.split(data)
in Array if data.all? { _1 in RawText | Literal }
else
raise TypeError, "expected String or Array[#{RawText} | #{Literal}]"
end
super
validate
end
Expand All @@ -212,9 +217,11 @@ def validate
end
end

private

def split_parts(data)
# Splits an input +string+ into an array of RawText and Literal/Literal8.
#
# NOTE: unlike RawData#validate, this does not prevent the final RawText
# from ending with a literal prefix.
def self.split(data)
data = data.b # dups and ensures BINARY encoding
parts = []
while data.match(/(~)?\{(0|[1-9]\d*)(\+)?\}\r\n/n)
Expand All @@ -228,14 +235,15 @@ def split_parts(data)
parts
end

def extract_literal(data, binary:, bytesize:, non_sync:)
def self.extract_literal(data, binary:, bytesize:, non_sync:)
if data.bytesize < bytesize
raise DataFormatError, "Too few bytes in string for literal, " \
"expected: %s, remaining: %s" % [bytesize, data.bytesize]
end
literal = data.byteslice(0, bytesize)
(binary ? Literal8 : Literal).new(data: literal, non_sync:)
end
private_class_method :extract_literal
end

class Atom < CommandData # :nodoc:
Expand Down
17 changes: 17 additions & 0 deletions test/net/imap/test_command_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,23 @@ class RawDataTest < CommandDataTest
raw = RawData.new(data: " {123} ")
assert_equal [RawText[" {123} "]], raw.data
end

data(
"simple raw text" => 'hello "world"',
"text, literal, text" => "OK {5}\r\nhello {5}\r\nworld",
"empty literals" => "{0}\r\n{0+}\r\n~{0}\r\n~{0+}\r\n",
"binary and regular" => "foo ~{7}\r\n\0bar\r\nbaz {4}\r\nquux",
)
test ".split" do |string|
assert_equal(RawData[string].data, RawData.split(string))
end

test ".split allows final literal prefix" do
assert_equal [RawText["text {123}"]], RawData.split("text {123}")
assert_equal [RawText["text+ {123+}"]], RawData.split("text+ {123+}")
assert_equal [RawText["~text ~{123}"]], RawData.split("~text ~{123}")
assert_equal [RawText["~text+ ~{123+}"]], RawData.split("~text+ ~{123+}")
end
end

end
Loading