This repository has been archived by the owner on Dec 5, 2023. It is now read-only.
forked from ConradIrwin/em-imap
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Import more of the command formatting from Net::IMAP
- Loading branch information
1 parent
fae44bc
commit 02e063e
Showing
3 changed files
with
198 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
module EventMachine | ||
module IMAP | ||
class Formatter | ||
|
||
# A placeholder so that the command sender knows to treat literal strings specially | ||
class Literal < Struct.new(:str); end | ||
|
||
# Format the data to be sent into strings and literals, and call the block | ||
# for each token to be sent. | ||
# | ||
# @param data The data to format, | ||
# @param &block The callback, which will be called with a number of strings and | ||
# EM::IMAP::Formatter::Literal instances. | ||
# | ||
# NOTE: The block is responsible for handling any network-level concerns, such | ||
# as sending literals only with permission. | ||
# | ||
def self.format(data, &block) | ||
new(&block).send_data(data) | ||
end | ||
|
||
def initialize(&block) | ||
@block = block | ||
end | ||
|
||
def put_string(str) | ||
@block.call str | ||
end | ||
|
||
def send_literal(str) | ||
@block.call Literal.new(str) | ||
end | ||
|
||
# The remainder of the code in this file is directly from Net::IMAP. | ||
# Copyright (C) 2000 Shugo Maeda <shugo@ruby-lang.org> | ||
def send_data(data) | ||
case data | ||
when nil | ||
put_string("NIL") | ||
when String | ||
send_string_data(data) | ||
when Integer | ||
send_number_data(data) | ||
when Array | ||
send_list_data(data) | ||
when Time | ||
send_time_data(data) | ||
when Symbol | ||
send_symbol_data(data) | ||
when EM::IMAP::Command | ||
send_command(data) | ||
else | ||
data.send_data(self) | ||
end | ||
end | ||
|
||
def send_command(cmd) | ||
put_string cmd.tag | ||
put_string " " | ||
put_string cmd.cmd | ||
cmd.args.each do |i| | ||
put_string " " | ||
send_data(i) | ||
end | ||
put_string "\r\n" | ||
end | ||
|
||
def send_string_data(str) | ||
case str | ||
when "" | ||
put_string('""') | ||
when /[\x80-\xff\r\n]/n | ||
# literal | ||
send_literal(str) | ||
when /[(){ \x00-\x1f\x7f%*"\\]/n | ||
# quoted string | ||
send_quoted_string(str) | ||
else | ||
put_string(str) | ||
end | ||
end | ||
|
||
def send_quoted_string(str) | ||
put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"') | ||
end | ||
|
||
def send_number_data(num) | ||
if num < 0 || num >= 4294967296 | ||
raise Net::IMAP::DataFormatError, num.to_s | ||
end | ||
put_string(num.to_s) | ||
end | ||
|
||
def send_list_data(list) | ||
put_string("(") | ||
first = true | ||
list.each do |i| | ||
if first | ||
first = false | ||
else | ||
put_string(" ") | ||
end | ||
send_data(i) | ||
end | ||
put_string(")") | ||
end | ||
|
||
DATE_MONTH = %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) | ||
|
||
def send_time_data(time) | ||
t = time.dup.gmtime | ||
s = format('"%2d-%3s-%4d %02d:%02d:%02d +0000"', | ||
t.day, DATE_MONTH[t.month - 1], t.year, | ||
t.hour, t.min, t.sec) | ||
put_string(s) | ||
end | ||
|
||
def send_symbol_data(symbol) | ||
put_string("\\" + symbol.to_s) | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
require 'spec_helper' | ||
describe EM::IMAP::Formatter do | ||
|
||
before do | ||
@result = [] | ||
@formatter = EM::IMAP::Formatter.new do |thing| | ||
if thing.is_a?(String) && @result.last.is_a?(String) | ||
@result[-1] += thing | ||
else | ||
@result << thing | ||
end | ||
end | ||
|
||
@format = lambda { |data| @result.tap{ @formatter.send_data data } } | ||
end | ||
|
||
it "should format nils" do | ||
@format.call(nil).should == ["NIL"] | ||
end | ||
|
||
it "should format simple strings with no quotes" do | ||
@format.call("FETCH").should == ["FETCH"] | ||
end | ||
|
||
it "should quote the empty string" do | ||
@format.call("").should == ['""'] | ||
end | ||
|
||
it "should quote strings with spaces" do | ||
@format.call("hello world").should == ['"hello world"'] | ||
end | ||
|
||
it "should make strings that contain newlines into literals" do | ||
@format.call("good\nmorning").should == [EM::IMAP::Formatter::Literal.new("good\nmorning")] | ||
end | ||
|
||
it "should raise an error on out-of-range ints" do | ||
lambda{ @format.call(2 ** 64) }.should raise_error Net::IMAP::DataFormatError | ||
lambda{ @format.call(-1) }.should raise_error Net::IMAP::DataFormatError | ||
end | ||
|
||
it "should be able to format in-range ints" do | ||
@format.call(123).should == ['123'] | ||
end | ||
|
||
it "should format dates with a leading space" do | ||
@format.call(Time.gm(2011, 1, 1, 10, 10, 10)).should == ['" 1-Jan-2011 10:10:10 +0000"'] | ||
end | ||
|
||
it "should format times in the 24 hour clock" do | ||
@format.call(Time.gm(2011, 10, 10, 19, 10, 10)).should == ['"10-Oct-2011 19:10:10 +0000"'] | ||
end | ||
|
||
it "should format lists correctly" do | ||
@format.call([1,"",nil, "three"]).should == ['(1 "" NIL three)'] | ||
end | ||
|
||
it "should allow for literals within lists" do | ||
@format.call(["oh yes", "oh\nno"]).should == ['("oh yes" ', EM::IMAP::Formatter::Literal.new("oh\nno"), ')'] | ||
end | ||
|
||
it "should format symbols correctly" do | ||
@format.call(:hi).should == ["\\hi"] | ||
end | ||
|
||
it "should format commands correctly" do | ||
@format.call(EM::IMAP::Command.new('RUBY0001', 'SELECT', ['Inbox'])).should == ["RUBY0001 SELECT Inbox\r\n"] | ||
end | ||
|
||
it "should format complex commands correctly" do | ||
@format.call(EM::IMAP::Command.new('RUBY1234', 'FETCH', [[Net::IMAP::MessageSet.new([1,2,3])], 'BODY'])).should == ["RUBY1234 FETCH (1,2,3) BODY\r\n"] | ||
end | ||
end |