Promote net-imap to the bundled gems

This commit is contained in:
Hiroshi SHIBATA 2021-05-26 15:48:36 +09:00
Родитель e49c998d1e
Коммит d5bc6b2337
21 изменённых файлов: 4 добавлений и 5706 удалений

Просмотреть файл

@ -158,10 +158,6 @@ Yukihiro Matsumoto (matz)
NARUSE, Yui (naruse)
https://github.com/ruby/net-http
https://rubygems.org/gems/net-http
[lib/net/imap.rb]
Shugo Maeda (shugo)
https://github.com/ruby/net-imap
https://rubygems.org/gems/net-imap
[lib/net/pop.rb]
_unmaintained_
https://github.com/ruby/net-pop
@ -389,6 +385,8 @@ Yukihiro Matsumoto (matz)
https://github.com/ruby/rss
[net-ftp]
https://github.com/ruby/net-ftp
[net-imap]
https://github.com/ruby/net-imap
[matrix]
https://github.com/ruby/matrix
[prime]

Просмотреть файл

@ -47,7 +47,6 @@ OptionParser:: Ruby-oriented class for command-line option analysis
Logger:: Provides a simple logging utility for outputting messages
Mutex_m:: Mixin to extend objects to be handled like a Mutex
Net::HTTP:: HTTP client api for Ruby
Net::IMAP:: Ruby client api for Internet Message Access Protocol
Net::POP3:: Ruby client library for POP3
Net::SMTP:: Simple Mail Transfer Protocol client library for Ruby
Observable:: Provides a mechanism for publish/subscribe pattern in Ruby
@ -109,6 +108,7 @@ Test::Unit:: A compatibility layer for MiniTest
REXML:: An XML toolkit for Ruby
RSS:: Family of libraries that support various formats of XML "feeds"
Net::FTP:: Support for the File Transfer Protocol
Net::IMAP:: Ruby client api for Internet Message Access Protocol
Matrix:: Represents a mathematical matrix.
Prime:: Prime numbers and factorization library
RBS:: RBS is a language to describe the structure of Ruby programs

Просмотреть файл

@ -6,6 +6,7 @@ test-unit 3.4.1 https://github.com/test-unit/test-unit 3.4.1
rexml 3.2.5 https://github.com/ruby/rexml
rss 0.2.9 https://github.com/ruby/rss 0.2.9
net-ftp 0.1.2 https://github.com/ruby/net-ftp
net-imap 0.2.1 https://github.com/ruby/net-imap
matrix 0.4.1 https://github.com/ruby/matrix
prime 0.1.2 https://github.com/ruby/prime
typeprof 0.14.1 https://github.com/ruby/typeprof

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,44 +0,0 @@
# frozen_string_literal: true
# Registry for SASL authenticators used by Net::IMAP.
module Net::IMAP::Authenticators
# Adds an authenticator for use with Net::IMAP#authenticate. +auth_type+ is the
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
# supported by +authenticator+ (for instance, "+PLAIN+"). The +authenticator+
# is an object which defines a +#process+ method to handle authentication with
# the server. See Net::IMAP::PlainAuthenticator, Net::IMAP::LoginAuthenticator,
# Net::IMAP::CramMD5Authenticator, and Net::IMAP::DigestMD5Authenticator for
# examples.
#
# If +auth_type+ refers to an existing authenticator, it will be
# replaced by the new one.
def add_authenticator(auth_type, authenticator)
authenticators[auth_type] = authenticator
end
# Builds an authenticator for Net::IMAP#authenticate. +args+ will be passed
# directly to the chosen authenticator's +#initialize+.
def authenticator(auth_type, *args)
auth_type = auth_type.upcase
unless authenticators.has_key?(auth_type)
raise ArgumentError,
format('unknown auth type - "%s"', auth_type)
end
authenticators[auth_type].new(*args)
end
private
def authenticators
@authenticators ||= {}
end
end
Net::IMAP.extend Net::IMAP::Authenticators
require_relative "authenticators/login"
require_relative "authenticators/plain"
require_relative "authenticators/cram_md5"
require_relative "authenticators/digest_md5"

Просмотреть файл

@ -1,49 +0,0 @@
# frozen_string_literal: true
require "digest/md5"
# Authenticator for the "+CRAM-MD5+" SASL mechanism, specified in
# RFC2195[https://tools.ietf.org/html/rfc2195]. See Net::IMAP#authenticate.
#
# == Deprecated
#
# +CRAM-MD5+ is obsolete and insecure. It is included for compatibility with
# existing servers.
# {draft-ietf-sasl-crammd5-to-historic}[https://tools.ietf.org/html/draft-ietf-sasl-crammd5-to-historic-00.html]
# recommends using +SCRAM-*+ or +PLAIN+ protected by TLS instead.
#
# Additionally, RFC8314[https://tools.ietf.org/html/rfc8314] discourage the use
# of cleartext and recommends TLS version 1.2 or greater be used for all
# traffic. With TLS +CRAM-MD5+ is okay, but so is +PLAIN+
class Net::IMAP::CramMD5Authenticator
def process(challenge)
digest = hmac_md5(challenge, @password)
return @user + " " + digest
end
private
def initialize(user, password)
@user = user
@password = password
end
def hmac_md5(text, key)
if key.length > 64
key = Digest::MD5.digest(key)
end
k_ipad = key + "\0" * (64 - key.length)
k_opad = key + "\0" * (64 - key.length)
for i in 0..63
k_ipad[i] = (k_ipad[i].ord ^ 0x36).chr
k_opad[i] = (k_opad[i].ord ^ 0x5c).chr
end
digest = Digest::MD5.digest(k_ipad + text)
return Digest::MD5.hexdigest(k_opad + digest)
end
Net::IMAP.add_authenticator "PLAIN", self
end

Просмотреть файл

@ -1,111 +0,0 @@
# frozen_string_literal: true
require "digest/md5"
require "strscan"
# Net::IMAP authenticator for the "`DIGEST-MD5`" SASL mechanism type, specified
# in RFC2831(https://tools.ietf.org/html/rfc2831). See Net::IMAP#authenticate.
#
# == Deprecated
#
# "+DIGEST-MD5+" has been deprecated by
# {RFC6331}[https://tools.ietf.org/html/rfc6331] and should not be relied on for
# security. It is included for compatibility with existing servers.
class Net::IMAP::DigestMD5Authenticator
def process(challenge)
case @stage
when STAGE_ONE
@stage = STAGE_TWO
sparams = {}
c = StringScanner.new(challenge)
while c.scan(/(?:\s*,)?\s*(\w+)=("(?:[^\\"]+|\\.)*"|[^,]+)\s*/)
k, v = c[1], c[2]
if v =~ /^"(.*)"$/
v = $1
if v =~ /,/
v = v.split(',')
end
end
sparams[k] = v
end
raise DataFormatError, "Bad Challenge: '#{challenge}'" unless c.rest.size == 0
raise Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
response = {
:nonce => sparams['nonce'],
:username => @user,
:realm => sparams['realm'],
:cnonce => Digest::MD5.hexdigest("%.15f:%.15f:%d" % [Time.now.to_f, rand, Process.pid.to_s]),
:'digest-uri' => 'imap/' + sparams['realm'],
:qop => 'auth',
:maxbuf => 65535,
:nc => "%08d" % nc(sparams['nonce']),
:charset => sparams['charset'],
}
response[:authzid] = @authname unless @authname.nil?
# now, the real thing
a0 = Digest::MD5.digest( [ response.values_at(:username, :realm), @password ].join(':') )
a1 = [ a0, response.values_at(:nonce,:cnonce) ].join(':')
a1 << ':' + response[:authzid] unless response[:authzid].nil?
a2 = "AUTHENTICATE:" + response[:'digest-uri']
a2 << ":00000000000000000000000000000000" if response[:qop] and response[:qop] =~ /^auth-(?:conf|int)$/
response[:response] = Digest::MD5.hexdigest(
[
Digest::MD5.hexdigest(a1),
response.values_at(:nonce, :nc, :cnonce, :qop),
Digest::MD5.hexdigest(a2)
].join(':')
)
return response.keys.map {|key| qdval(key.to_s, response[key]) }.join(',')
when STAGE_TWO
@stage = nil
# if at the second stage, return an empty string
if challenge =~ /rspauth=/
return ''
else
raise ResponseParseError, challenge
end
else
raise ResponseParseError, challenge
end
end
def initialize(user, password, authname = nil)
@user, @password, @authname = user, password, authname
@nc, @stage = {}, STAGE_ONE
end
private
STAGE_ONE = :stage_one
STAGE_TWO = :stage_two
def nc(nonce)
if @nc.has_key? nonce
@nc[nonce] = @nc[nonce] + 1
else
@nc[nonce] = 1
end
return @nc[nonce]
end
# some responses need quoting
def qdval(k, v)
return if k.nil? or v.nil?
if %w"username authzid realm nonce cnonce digest-uri qop".include? k
v.gsub!(/([\\"])/, "\\\1")
return '%s="%s"' % [k, v]
else
return '%s=%s' % [k, v]
end
end
Net::IMAP.add_authenticator "DIGEST-MD5", self
end

Просмотреть файл

@ -1,43 +0,0 @@
# frozen_string_literal: true
# Authenticator for the "+LOGIN+" SASL mechanism. See Net::IMAP#authenticate.
#
# +LOGIN+ authentication sends the password in cleartext.
# RFC3501[https://tools.ietf.org/html/rfc3501] encourages servers to disable
# cleartext authentication until after TLS has been negotiated.
# RFC8314[https://tools.ietf.org/html/rfc8314] recommends TLS version 1.2 or
# greater be used for all traffic, and deprecate cleartext access ASAP. +LOGIN+
# can be secured by TLS encryption.
#
# == Deprecated
#
# The {SASL mechanisms
# registry}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
# marks "LOGIN" as obsoleted in favor of "PLAIN". It is included here for
# compatibility with existing servers. See
# {draft-murchison-sasl-login}[https://www.iana.org/go/draft-murchison-sasl-login]
# for both specification and deprecation.
class Net::IMAP::LoginAuthenticator
def process(data)
case @state
when STATE_USER
@state = STATE_PASSWORD
return @user
when STATE_PASSWORD
return @password
end
end
private
STATE_USER = :USER
STATE_PASSWORD = :PASSWORD
def initialize(user, password)
@user = user
@password = password
@state = STATE_USER
end
Net::IMAP.add_authenticator "LOGIN", self
end

Просмотреть файл

@ -1,41 +0,0 @@
# frozen_string_literal: true
# Authenticator for the "+PLAIN+" SASL mechanism, specified in
# RFC4616[https://tools.ietf.org/html/rfc4616]. See Net::IMAP#authenticate.
#
# +PLAIN+ authentication sends the password in cleartext.
# RFC3501[https://tools.ietf.org/html/rfc3501] encourages servers to disable
# cleartext authentication until after TLS has been negotiated.
# RFC8314[https://tools.ietf.org/html/rfc8314] recommends TLS version 1.2 or
# greater be used for all traffic, and deprecate cleartext access ASAP. +PLAIN+
# can be secured by TLS encryption.
class Net::IMAP::PlainAuthenticator
def process(data)
return "#@authzid\0#@username\0#@password"
end
# :nodoc:
NULL = -"\0".b
private
# +username+ is the authentication identity, the identity whose +password+ is
# used. +username+ is referred to as +authcid+ by
# RFC4616[https://tools.ietf.org/html/rfc4616].
#
# +authzid+ is the authorization identity (identity to act as). It can
# usually be left blank. When +authzid+ is left blank (nil or empty string)
# the server will derive an identity from the credentials and use that as the
# authorization identity.
def initialize(username, password, authzid: nil)
raise ArgumentError, "username contains NULL" if username&.include?(NULL)
raise ArgumentError, "password contains NULL" if password&.include?(NULL)
raise ArgumentError, "authzid contains NULL" if authzid&.include?(NULL)
@username = username
@password = password
@authzid = authzid
end
Net::IMAP.add_authenticator "PLAIN", self
end

Просмотреть файл

@ -1,301 +0,0 @@
# frozen_string_literal: true
module Net
class IMAP < Protocol
private
def validate_data(data)
case data
when nil
when String
when Integer
NumValidator.ensure_number(data)
when Array
if data[0] == 'CHANGEDSINCE'
NumValidator.ensure_mod_sequence_value(data[1])
else
data.each do |i|
validate_data(i)
end
end
when Time
when Symbol
else
data.validate
end
end
def send_data(data, tag = nil)
case data
when nil
put_string("NIL")
when String
send_string_data(data, tag)
when Integer
send_number_data(data)
when Array
send_list_data(data, tag)
when Time
send_time_data(data)
when Symbol
send_symbol_data(data)
else
data.send_data(self, tag)
end
end
def send_string_data(str, tag = nil)
case str
when ""
put_string('""')
when /[\x80-\xff\r\n]/n
# literal
send_literal(str, tag)
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_literal(str, tag = nil)
synchronize do
put_string("{" + str.bytesize.to_s + "}" + CRLF)
@continued_command_tag = tag
@continuation_request_exception = nil
begin
@continuation_request_arrival.wait
e = @continuation_request_exception || @exception
raise e if e
put_string(str)
ensure
@continued_command_tag = nil
@continuation_request_exception = nil
end
end
end
def send_number_data(num)
put_string(num.to_s)
end
def send_list_data(list, tag = nil)
put_string("(")
first = true
list.each do |i|
if first
first = false
else
put_string(" ")
end
send_data(i, tag)
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
class RawData # :nodoc:
def send_data(imap, tag)
imap.__send__(:put_string, @data)
end
def validate
end
private
def initialize(data)
@data = data
end
end
class Atom # :nodoc:
def send_data(imap, tag)
imap.__send__(:put_string, @data)
end
def validate
end
private
def initialize(data)
@data = data
end
end
class QuotedString # :nodoc:
def send_data(imap, tag)
imap.__send__(:send_quoted_string, @data)
end
def validate
end
private
def initialize(data)
@data = data
end
end
class Literal # :nodoc:
def send_data(imap, tag)
imap.__send__(:send_literal, @data, tag)
end
def validate
end
private
def initialize(data)
@data = data
end
end
class MessageSet # :nodoc:
def send_data(imap, tag)
imap.__send__(:put_string, format_internal(@data))
end
def validate
validate_internal(@data)
end
private
def initialize(data)
@data = data
end
def format_internal(data)
case data
when "*"
return data
when Integer
if data == -1
return "*"
else
return data.to_s
end
when Range
return format_internal(data.first) +
":" + format_internal(data.last)
when Array
return data.collect {|i| format_internal(i)}.join(",")
when ThreadMember
return data.seqno.to_s +
":" + data.children.collect {|i| format_internal(i).join(",")}
end
end
def validate_internal(data)
case data
when "*"
when Integer
NumValidator.ensure_nz_number(data)
when Range
when Array
data.each do |i|
validate_internal(i)
end
when ThreadMember
data.children.each do |i|
validate_internal(i)
end
else
raise DataFormatError, data.inspect
end
end
end
class ClientID # :nodoc:
def send_data(imap, tag)
imap.__send__(:send_data, format_internal(@data), tag)
end
def validate
validate_internal(@data)
end
private
def initialize(data)
@data = data
end
def validate_internal(client_id)
client_id.to_h.each do |k,v|
unless StringFormatter.valid_string?(k)
raise DataFormatError, client_id.inspect
end
end
rescue NoMethodError, TypeError # to_h failed
raise DataFormatError, client_id.inspect
end
def format_internal(client_id)
return nil if client_id.nil?
client_id.to_h.flat_map {|k,v|
[StringFormatter.string(k), StringFormatter.nstring(v)]
}
end
end
module StringFormatter
LITERAL_REGEX = /[\x80-\xff\r\n]/n
module_function
# Allows symbols in addition to strings
def valid_string?(str)
str.is_a?(Symbol) || str.respond_to?(:to_str)
end
# Allows nil, symbols, and strings
def valid_nstring?(str)
str.nil? || valid_string?(str)
end
# coerces using +to_s+
def string(str)
str = str.to_s
if str =~ LITERAL_REGEX
Literal.new(str)
else
QuotedString.new(str)
end
end
# coerces non-nil using +to_s+
def nstring(str)
str.nil? ? nil : string(str)
end
end
end
end

Просмотреть файл

@ -1,47 +0,0 @@
# frozen_string_literal: true
module Net
class IMAP < Protocol
# Decode a string from modified UTF-7 format to UTF-8.
#
# UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a
# slightly modified version of this to encode mailbox names
# containing non-ASCII characters; see [IMAP] section 5.1.3.
#
# Net::IMAP does _not_ automatically encode and decode
# mailbox names to and from UTF-7.
def self.decode_utf7(s)
return s.gsub(/&([^-]+)?-/n) {
if $1
($1.tr(",", "/") + "===").unpack1("m").encode(Encoding::UTF_8, Encoding::UTF_16BE)
else
"&"
end
}
end
# Encode a string from UTF-8 format to modified UTF-7.
def self.encode_utf7(s)
return s.gsub(/(&)|[^\x20-\x7e]+/) {
if $1
"&-"
else
base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0")
"&" + base64.delete("=").tr("/", ",") + "-"
end
}.force_encoding("ASCII-8BIT")
end
# Formats +time+ as an IMAP-style date.
def self.format_date(time)
return time.strftime('%d-%b-%Y')
end
# Formats +time+ as an IMAP-style date-time.
def self.format_datetime(time)
return time.strftime('%d-%b-%Y %H:%M %z')
end
end
end

Просмотреть файл

@ -1,76 +0,0 @@
# frozen_string_literal: true
module Net
class IMAP < Protocol
# :category: Message Flags
#
# Flag indicating a message has been seen.
SEEN = :Seen
# :category: Message Flags
#
# Flag indicating a message has been answered.
ANSWERED = :Answered
# :category: Message Flags
#
# Flag indicating a message has been flagged for special or urgent
# attention.
FLAGGED = :Flagged
# :category: Message Flags
#
# Flag indicating a message has been marked for deletion. This
# will occur when the mailbox is closed or expunged.
DELETED = :Deleted
# :category: Message Flags
#
# Flag indicating a message is only a draft or work-in-progress version.
DRAFT = :Draft
# :category: Message Flags
#
# Flag indicating that the message is "recent," meaning that this
# session is the first session in which the client has been notified
# of this message.
RECENT = :Recent
# :category: Mailbox Flags
#
# Flag indicating that a mailbox context name cannot contain
# children.
NOINFERIORS = :Noinferiors
# :category: Mailbox Flags
#
# Flag indicating that a mailbox is not selected.
NOSELECT = :Noselect
# :category: Mailbox Flags
#
# Flag indicating that a mailbox has been marked "interesting" by
# the server; this commonly indicates that the mailbox contains
# new messages.
MARKED = :Marked
# :category: Mailbox Flags
#
# Flag indicating that the mailbox does not contains new messages.
UNMARKED = :Unmarked
@@max_flag_count = 10000
# Returns the max number of flags interned to symbols.
def self.max_flag_count
return @@max_flag_count
end
# Sets the max number of flags interned to symbols.
def self.max_flag_count=(count)
@@max_flag_count = count
end
end
end

Просмотреть файл

@ -1,37 +0,0 @@
# frozen_string_literal: true
name = File.basename(__FILE__, ".gemspec")
version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
end rescue nil
end
Gem::Specification.new do |spec|
spec.name = name
spec.version = version
spec.authors = ["Shugo Maeda"]
spec.email = ["shugo@ruby-lang.org"]
spec.summary = %q{Ruby client api for Internet Message Access Protocol}
spec.description = %q{Ruby client api for Internet Message Access Protocol}
spec.homepage = "https://github.com/ruby/net-imap"
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
`git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_dependency "net-protocol"
spec.add_dependency "digest"
spec.add_dependency "strscan"
end

Просмотреть файл

@ -1,527 +0,0 @@
# frozen_string_literal: true
module Net
class IMAP < Protocol
# Net::IMAP::ContinuationRequest represents command continuation requests.
#
# The command continuation request response is indicated by a "+" token
# instead of a tag. This form of response indicates that the server is
# ready to accept the continuation of a command from the client. The
# remainder of this response is a line of text.
#
# continue_req ::= "+" SPACE (resp_text / base64)
#
# ==== Fields:
#
# data:: Returns the data (Net::IMAP::ResponseText).
#
# raw_data:: Returns the raw data string.
class ContinuationRequest < Struct.new(:data, :raw_data)
end
# Net::IMAP::UntaggedResponse represents untagged responses.
#
# Data transmitted by the server to the client and status responses
# that do not indicate command completion are prefixed with the token
# "*", and are called untagged responses.
#
# response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
# mailbox_data / message_data / capability_data)
#
# ==== Fields:
#
# name:: Returns the name, such as "FLAGS", "LIST", or "FETCH".
#
# data:: Returns the data such as an array of flag symbols,
# a ((<Net::IMAP::MailboxList>)) object.
#
# raw_data:: Returns the raw data string.
class UntaggedResponse < Struct.new(:name, :data, :raw_data)
end
# Net::IMAP::IgnoredResponse represents intentionally ignored responses.
#
# This includes untagged response "NOOP" sent by eg. Zimbra to avoid some
# clients to close the connection.
#
# It matches no IMAP standard.
#
# ==== Fields:
#
# raw_data:: Returns the raw data string.
class IgnoredResponse < Struct.new(:raw_data)
end
# Net::IMAP::TaggedResponse represents tagged responses.
#
# The server completion result response indicates the success or
# failure of the operation. It is tagged with the same tag as the
# client command which began the operation.
#
# response_tagged ::= tag SPACE resp_cond_state CRLF
#
# tag ::= 1*<any ATOM_CHAR except "+">
#
# resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
#
# ==== Fields:
#
# tag:: Returns the tag.
#
# name:: Returns the name, one of "OK", "NO", or "BAD".
#
# data:: Returns the data. See ((<Net::IMAP::ResponseText>)).
#
# raw_data:: Returns the raw data string.
#
class TaggedResponse < Struct.new(:tag, :name, :data, :raw_data)
end
# Net::IMAP::ResponseText represents texts of responses.
# The text may be prefixed by the response code.
#
# resp_text ::= ["[" resp-text-code "]" SP] text
#
# ==== Fields:
#
# code:: Returns the response code. See ((<Net::IMAP::ResponseCode>)).
#
# text:: Returns the text.
#
class ResponseText < Struct.new(:code, :text)
end
# Net::IMAP::ResponseCode represents response codes.
#
# resp_text_code ::= "ALERT" /
# "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
# capability_data / "PARSE" /
# "PERMANENTFLAGS" SP "("
# [flag_perm *(SP flag_perm)] ")" /
# "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
# "UIDNEXT" SP nz_number / "UIDVALIDITY" SP nz_number /
# "UNSEEN" SP nz_number /
# atom [SP 1*<any TEXT-CHAR except "]">]
#
# ==== Fields:
#
# name:: Returns the name, such as "ALERT", "PERMANENTFLAGS", or "UIDVALIDITY".
#
# data:: Returns the data, if it exists.
#
class ResponseCode < Struct.new(:name, :data)
end
# Net::IMAP::MailboxList represents contents of the LIST response.
#
# mailbox_list ::= "(" #("\Marked" / "\Noinferiors" /
# "\Noselect" / "\Unmarked" / flag_extension) ")"
# SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
#
# ==== Fields:
#
# attr:: Returns the name attributes. Each name attribute is a symbol
# capitalized by String#capitalize, such as :Noselect (not :NoSelect).
#
# delim:: Returns the hierarchy delimiter.
#
# name:: Returns the mailbox name.
#
class MailboxList < Struct.new(:attr, :delim, :name)
end
# Net::IMAP::MailboxQuota represents contents of GETQUOTA response.
# This object can also be a response to GETQUOTAROOT. In the syntax
# specification below, the delimiter used with the "#" construct is a
# single space (SPACE).
#
# quota_list ::= "(" #quota_resource ")"
#
# quota_resource ::= atom SPACE number SPACE number
#
# quota_response ::= "QUOTA" SPACE astring SPACE quota_list
#
# ==== Fields:
#
# mailbox:: The mailbox with the associated quota.
#
# usage:: Current storage usage of the mailbox.
#
# quota:: Quota limit imposed on the mailbox.
#
class MailboxQuota < Struct.new(:mailbox, :usage, :quota)
end
# Net::IMAP::MailboxQuotaRoot represents part of the GETQUOTAROOT
# response. (GETQUOTAROOT can also return Net::IMAP::MailboxQuota.)
#
# quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring)
#
# ==== Fields:
#
# mailbox:: The mailbox with the associated quota.
#
# quotaroots:: Zero or more quotaroots that affect the quota on the
# specified mailbox.
#
class MailboxQuotaRoot < Struct.new(:mailbox, :quotaroots)
end
# Net::IMAP::MailboxACLItem represents the response from GETACL.
#
# acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights)
#
# identifier ::= astring
#
# rights ::= astring
#
# ==== Fields:
#
# user:: Login name that has certain rights to the mailbox
# that was specified with the getacl command.
#
# rights:: The access rights the indicated user has to the
# mailbox.
#
class MailboxACLItem < Struct.new(:user, :rights, :mailbox)
end
# Net::IMAP::Namespace represents a single [RFC-2342] namespace.
#
# Namespace = nil / "(" 1*( "(" string SP (<"> QUOTED_CHAR <"> /
# nil) *(Namespace_Response_Extension) ")" ) ")"
#
# Namespace_Response_Extension = SP string SP "(" string *(SP string)
# ")"
#
# ==== Fields:
#
# prefix:: Returns the namespace prefix string.
# delim:: Returns nil or the hierarchy delimiter character.
# extensions:: Returns a hash of extension names to extension flag arrays.
#
class Namespace < Struct.new(:prefix, :delim, :extensions)
end
# Net::IMAP::Namespaces represents the response from [RFC-2342] NAMESPACE.
#
# Namespace_Response = "*" SP "NAMESPACE" SP Namespace SP Namespace SP
# Namespace
#
# ; The first Namespace is the Personal Namespace(s)
# ; The second Namespace is the Other Users' Namespace(s)
# ; The third Namespace is the Shared Namespace(s)
#
# ==== Fields:
#
# personal:: Returns an array of Personal Net::IMAP::Namespace objects.
# other:: Returns an array of Other Users' Net::IMAP::Namespace objects.
# shared:: Returns an array of Shared Net::IMAP::Namespace objects.
#
class Namespaces < Struct.new(:personal, :other, :shared)
end
# Net::IMAP::StatusData represents the contents of the STATUS response.
#
# ==== Fields:
#
# mailbox:: Returns the mailbox name.
#
# attr:: Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT",
# "UIDVALIDITY", "UNSEEN". Each value is a number.
#
class StatusData < Struct.new(:mailbox, :attr)
end
# Net::IMAP::FetchData represents the contents of the FETCH response.
#
# ==== Fields:
#
# seqno:: Returns the message sequence number.
# (Note: not the unique identifier, even for the UID command response.)
#
# attr:: Returns a hash. Each key is a data item name, and each value is
# its value.
#
# The current data items are:
#
# [BODY]
# A form of BODYSTRUCTURE without extension data.
# [BODY[<section>]<<origin_octet>>]
# A string expressing the body contents of the specified section.
# [BODYSTRUCTURE]
# An object that describes the [MIME-IMB] body structure of a message.
# See Net::IMAP::BodyTypeBasic, Net::IMAP::BodyTypeText,
# Net::IMAP::BodyTypeMessage, Net::IMAP::BodyTypeMultipart.
# [ENVELOPE]
# A Net::IMAP::Envelope object that describes the envelope
# structure of a message.
# [FLAGS]
# A array of flag symbols that are set for this message. Flag symbols
# are capitalized by String#capitalize.
# [INTERNALDATE]
# A string representing the internal date of the message.
# [RFC822]
# Equivalent to +BODY[]+.
# [RFC822.HEADER]
# Equivalent to +BODY.PEEK[HEADER]+.
# [RFC822.SIZE]
# A number expressing the [RFC-822] size of the message.
# [RFC822.TEXT]
# Equivalent to +BODY[TEXT]+.
# [UID]
# A number expressing the unique identifier of the message.
#
class FetchData < Struct.new(:seqno, :attr)
end
# Net::IMAP::Envelope represents envelope structures of messages.
#
# ==== Fields:
#
# date:: Returns a string that represents the date.
#
# subject:: Returns a string that represents the subject.
#
# from:: Returns an array of Net::IMAP::Address that represents the from.
#
# sender:: Returns an array of Net::IMAP::Address that represents the sender.
#
# reply_to:: Returns an array of Net::IMAP::Address that represents the reply-to.
#
# to:: Returns an array of Net::IMAP::Address that represents the to.
#
# cc:: Returns an array of Net::IMAP::Address that represents the cc.
#
# bcc:: Returns an array of Net::IMAP::Address that represents the bcc.
#
# in_reply_to:: Returns a string that represents the in-reply-to.
#
# message_id:: Returns a string that represents the message-id.
#
class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to,
:to, :cc, :bcc, :in_reply_to, :message_id)
end
#
# Net::IMAP::Address represents electronic mail addresses.
#
# ==== Fields:
#
# name:: Returns the phrase from [RFC-822] mailbox.
#
# route:: Returns the route from [RFC-822] route-addr.
#
# mailbox:: nil indicates end of [RFC-822] group.
# If non-nil and host is nil, returns [RFC-822] group name.
# Otherwise, returns [RFC-822] local-part.
#
# host:: nil indicates [RFC-822] group syntax.
# Otherwise, returns [RFC-822] domain name.
#
class Address < Struct.new(:name, :route, :mailbox, :host)
end
#
# Net::IMAP::ContentDisposition represents Content-Disposition fields.
#
# ==== Fields:
#
# dsp_type:: Returns the disposition type.
#
# param:: Returns a hash that represents parameters of the Content-Disposition
# field.
#
class ContentDisposition < Struct.new(:dsp_type, :param)
end
# Net::IMAP::ThreadMember represents a thread-node returned
# by Net::IMAP#thread.
#
# ==== Fields:
#
# seqno:: The sequence number of this message.
#
# children:: An array of Net::IMAP::ThreadMember objects for mail
# items that are children of this in the thread.
#
class ThreadMember < Struct.new(:seqno, :children)
end
# Net::IMAP::BodyTypeBasic represents basic body structures of messages.
#
# ==== Fields:
#
# media_type:: Returns the content media type name as defined in [MIME-IMB].
#
# subtype:: Returns the content subtype name as defined in [MIME-IMB].
#
# param:: Returns a hash that represents parameters as defined in [MIME-IMB].
#
# content_id:: Returns a string giving the content id as defined in [MIME-IMB].
#
# description:: Returns a string giving the content description as defined in
# [MIME-IMB].
#
# encoding:: Returns a string giving the content transfer encoding as defined in
# [MIME-IMB].
#
# size:: Returns a number giving the size of the body in octets.
#
# md5:: Returns a string giving the body MD5 value as defined in [MD5].
#
# disposition:: Returns a Net::IMAP::ContentDisposition object giving
# the content disposition.
#
# language:: Returns a string or an array of strings giving the body
# language value as defined in [LANGUAGE-TAGS].
#
# extension:: Returns extension data.
#
# multipart?:: Returns false.
#
class BodyTypeBasic < Struct.new(:media_type, :subtype,
:param, :content_id,
:description, :encoding, :size,
:md5, :disposition, :language,
:extension)
def multipart?
return false
end
# Obsolete: use +subtype+ instead. Calling this will
# generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
return subtype
end
end
# Net::IMAP::BodyTypeText represents TEXT body structures of messages.
#
# ==== Fields:
#
# lines:: Returns the size of the body in text lines.
#
# And Net::IMAP::BodyTypeText has all fields of Net::IMAP::BodyTypeBasic.
#
class BodyTypeText < Struct.new(:media_type, :subtype,
:param, :content_id,
:description, :encoding, :size,
:lines,
:md5, :disposition, :language,
:extension)
def multipart?
return false
end
# Obsolete: use +subtype+ instead. Calling this will
# generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
return subtype
end
end
# Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages.
#
# ==== Fields:
#
# envelope:: Returns a Net::IMAP::Envelope giving the envelope structure.
#
# body:: Returns an object giving the body structure.
#
# And Net::IMAP::BodyTypeMessage has all methods of Net::IMAP::BodyTypeText.
#
class BodyTypeMessage < Struct.new(:media_type, :subtype,
:param, :content_id,
:description, :encoding, :size,
:envelope, :body, :lines,
:md5, :disposition, :language,
:extension)
def multipart?
return false
end
# Obsolete: use +subtype+ instead. Calling this will
# generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
return subtype
end
end
# Net::IMAP::BodyTypeAttachment represents attachment body structures
# of messages.
#
# ==== Fields:
#
# media_type:: Returns the content media type name.
#
# subtype:: Returns +nil+.
#
# param:: Returns a hash that represents parameters.
#
# multipart?:: Returns false.
#
class BodyTypeAttachment < Struct.new(:media_type, :subtype,
:param)
def multipart?
return false
end
end
# Net::IMAP::BodyTypeMultipart represents multipart body structures
# of messages.
#
# ==== Fields:
#
# media_type:: Returns the content media type name as defined in [MIME-IMB].
#
# subtype:: Returns the content subtype name as defined in [MIME-IMB].
#
# parts:: Returns multiple parts.
#
# param:: Returns a hash that represents parameters as defined in [MIME-IMB].
#
# disposition:: Returns a Net::IMAP::ContentDisposition object giving
# the content disposition.
#
# language:: Returns a string or an array of strings giving the body
# language value as defined in [LANGUAGE-TAGS].
#
# extension:: Returns extension data.
#
# multipart?:: Returns true.
#
class BodyTypeMultipart < Struct.new(:media_type, :subtype,
:parts,
:param, :disposition, :language,
:extension)
def multipart?
return true
end
# Obsolete: use +subtype+ instead. Calling this will
# generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
return subtype
end
end
class BodyTypeExtension < Struct.new(:media_type, :subtype,
:params, :content_id,
:description, :encoding, :size)
def multipart?
return false
end
end
end
end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -80,7 +80,6 @@ DEFAULT_GEM_LIBS = %w[
logger
mutex_m
net-http
net-imap
net-pop
net-protocol
net-smtp

Просмотреть файл

@ -1,856 +0,0 @@
# frozen_string_literal: true
require "net/imap"
require "test/unit"
class IMAPTest < Test::Unit::TestCase
CA_FILE = File.expand_path("../fixtures/cacert.pem", __dir__)
SERVER_KEY = File.expand_path("../fixtures/server.key", __dir__)
SERVER_CERT = File.expand_path("../fixtures/server.crt", __dir__)
def setup
@do_not_reverse_lookup = Socket.do_not_reverse_lookup
Socket.do_not_reverse_lookup = true
@threads = []
end
def teardown
if !@threads.empty?
assert_join_threads(@threads)
end
ensure
Socket.do_not_reverse_lookup = @do_not_reverse_lookup
end
if defined?(OpenSSL::SSL::SSLError)
def test_imaps_unknown_ca
assert_raise(OpenSSL::SSL::SSLError) do
imaps_test do |port|
begin
Net::IMAP.new("localhost",
:port => port,
:ssl => true)
rescue SystemCallError
skip $!
end
end
end
end
def test_imaps_with_ca_file
assert_nothing_raised do
imaps_test do |port|
begin
Net::IMAP.new("localhost",
:port => port,
:ssl => { :ca_file => CA_FILE })
rescue SystemCallError
skip $!
end
end
end
end
def test_imaps_verify_none
assert_nothing_raised do
imaps_test do |port|
Net::IMAP.new(server_addr,
:port => port,
:ssl => { :verify_mode => OpenSSL::SSL::VERIFY_NONE })
end
end
end
def test_imaps_post_connection_check
assert_raise(OpenSSL::SSL::SSLError) do
imaps_test do |port|
# server_addr is different from the hostname in the certificate,
# so the following code should raise a SSLError.
Net::IMAP.new(server_addr,
:port => port,
:ssl => { :ca_file => CA_FILE })
end
end
end
end
if defined?(OpenSSL::SSL)
def test_starttls
imap = nil
starttls_test do |port|
imap = Net::IMAP.new("localhost", :port => port)
imap.starttls(:ca_file => CA_FILE)
imap
end
rescue SystemCallError
skip $!
ensure
if imap && !imap.disconnected?
imap.disconnect
end
end
end
def start_server
th = Thread.new do
yield
end
@threads << th
sleep 0.1 until th.stop?
end
def test_unexpected_eof
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
sock.gets
# sock.print("* BYE terminating connection\r\n")
# sock.print("RUBY0001 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
assert_raise(EOFError) do
imap.logout
end
ensure
imap.disconnect if imap
end
end
def test_idle
server = create_tcp_server
port = server.addr[1]
requests = []
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
requests.push(sock.gets)
sock.print("+ idling\r\n")
sock.print("* 3 EXISTS\r\n")
sock.print("* 2 EXPUNGE\r\n")
requests.push(sock.gets)
sock.print("RUBY0001 OK IDLE terminated\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
responses = []
imap.idle do |res|
responses.push(res)
if res.name == "EXPUNGE"
imap.idle_done
end
end
assert_equal(3, responses.length)
assert_instance_of(Net::IMAP::ContinuationRequest, responses[0])
assert_equal("EXISTS", responses[1].name)
assert_equal(3, responses[1].data)
assert_equal("EXPUNGE", responses[2].name)
assert_equal(2, responses[2].data)
assert_equal(2, requests.length)
assert_equal("RUBY0001 IDLE\r\n", requests[0])
assert_equal("DONE\r\n", requests[1])
imap.logout
ensure
imap.disconnect if imap
end
end
def test_exception_during_idle
server = create_tcp_server
port = server.addr[1]
requests = []
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
requests.push(sock.gets)
sock.print("+ idling\r\n")
sock.print("* 3 EXISTS\r\n")
sock.print("* 2 EXPUNGE\r\n")
requests.push(sock.gets)
sock.print("RUBY0001 OK IDLE terminated\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
begin
th = Thread.current
m = Monitor.new
in_idle = false
exception_raised = false
c = m.new_cond
raiser = Thread.start do
m.synchronize do
until in_idle
c.wait(0.1)
end
end
th.raise(Interrupt)
m.synchronize do
exception_raised = true
c.signal
end
end
@threads << raiser
imap.idle do |res|
m.synchronize do
in_idle = true
c.signal
until exception_raised
c.wait(0.1)
end
end
end
rescue Interrupt
end
assert_equal(2, requests.length)
assert_equal("RUBY0001 IDLE\r\n", requests[0])
assert_equal("DONE\r\n", requests[1])
imap.logout
ensure
imap.disconnect if imap
raiser.kill unless in_idle
end
end
def test_idle_done_not_during_idle
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
sleep 0.1
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
assert_raise(Net::IMAP::Error) do
imap.idle_done
end
ensure
imap.disconnect if imap
end
end
def test_idle_timeout
server = create_tcp_server
port = server.addr[1]
requests = []
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
requests.push(sock.gets)
sock.print("+ idling\r\n")
sock.print("* 3 EXISTS\r\n")
sock.print("* 2 EXPUNGE\r\n")
requests.push(sock.gets)
sock.print("RUBY0001 OK IDLE terminated\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
responses = []
Thread.pass
imap.idle(0.2) do |res|
responses.push(res)
end
# There is no guarantee that this thread has received all the responses,
# so check the response length.
if responses.length > 0
assert_instance_of(Net::IMAP::ContinuationRequest, responses[0])
if responses.length > 1
assert_equal("EXISTS", responses[1].name)
assert_equal(3, responses[1].data)
if responses.length > 2
assert_equal("EXPUNGE", responses[2].name)
assert_equal(2, responses[2].data)
end
end
end
# Also, there is no guarantee that the server thread has stored
# all the requests into the array, so check the length.
if requests.length > 0
assert_equal("RUBY0001 IDLE\r\n", requests[0])
if requests.length > 1
assert_equal("DONE\r\n", requests[1])
end
end
imap.logout
ensure
imap.disconnect if imap
end
end
def test_unexpected_bye
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK Gimap ready for requests from 75.101.246.151 33if2752585qyk.26\r\n")
sock.gets
sock.print("* BYE System Error 33if2752585qyk.26\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
assert_raise(Net::IMAP::ByeResponseError) do
imap.login("user", "password")
end
end
end
def test_exception_during_shutdown
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0001 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
imap.instance_eval do
def @sock.shutdown(*args)
super
ensure
raise "error"
end
end
imap.logout
ensure
assert_raise(RuntimeError) do
imap.disconnect
end
end
end
def test_connection_closed_during_idle
server = create_tcp_server
port = server.addr[1]
requests = []
sock = nil
threads = []
started = false
threads << Thread.start do
started = true
begin
sock = server.accept
sock.print("* OK test server\r\n")
requests.push(sock.gets)
sock.print("+ idling\r\n")
rescue IOError # sock is closed by another thread
ensure
server.close
end
end
sleep 0.1 until started
threads << Thread.start do
imap = Net::IMAP.new(server_addr, :port => port)
begin
m = Monitor.new
in_idle = false
closed = false
c = m.new_cond
threads << Thread.start do
m.synchronize do
until in_idle
c.wait(0.1)
end
end
sock.close
m.synchronize do
closed = true
c.signal
end
end
assert_raise(EOFError) do
imap.idle do |res|
m.synchronize do
in_idle = true
c.signal
until closed
c.wait(0.1)
end
end
end
end
assert_equal(1, requests.length)
assert_equal("RUBY0001 IDLE\r\n", requests[0])
ensure
imap.disconnect if imap
end
end
assert_join_threads(threads)
ensure
if sock && !sock.closed?
sock.close
end
end
def test_connection_closed_without_greeting
server = create_tcp_server
port = server.addr[1]
h = {
server: server,
port: port,
server_created: {
server: server.inspect,
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
}
}
net_imap = Class.new(Net::IMAP) do
@@h = h
def tcp_socket(host, port)
@@h[:in_tcp_socket] = {
host: host,
port: port,
server: @@h[:server].inspect,
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
}
#super
s = Socket.tcp(host, port, :connect_timeout => @open_timeout)
@@h[:in_tcp_socket_2] = {
s: s.inspect,
local_address: s.local_address,
remote_address: s.remote_address,
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
}
s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true)
s
end
end
start_server do
begin
h[:in_start_server_before_accept] = {
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
}
sock = server.accept
h[:in_start_server] = {
sock_addr: sock.addr,
sock_peeraddr: sock.peeraddr,
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
sockets: ObjectSpace.each_object(BasicSocket).map{|s| [s.inspect, connect_address: (s.connect_address rescue nil).inspect, local_address: (s.local_address rescue nil).inspect, remote_address: (s.remote_address rescue nil).inspect] },
}
sock.close
h[:in_start_server_sock_closed] = {
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
}
ensure
server.close
end
end
assert_raise(Net::IMAP::Error) do
#Net::IMAP.new(server_addr, :port => port)
if true
net_imap.new(server_addr, :port => port)
else
# for testing debug print
begin
net_imap.new(server_addr, :port => port)
rescue Net::IMAP::Error
raise Errno::EINVAL
end
end
rescue SystemCallError => e # for debug on OpenCSW
h[:in_rescue] = {
e: e,
server_addr: server_addr,
t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
}
require 'pp'
raise(PP.pp(h, +''))
end
end
def test_default_port
assert_equal(143, Net::IMAP.default_port)
assert_equal(143, Net::IMAP.default_imap_port)
assert_equal(993, Net::IMAP.default_tls_port)
assert_equal(993, Net::IMAP.default_ssl_port)
assert_equal(993, Net::IMAP.default_imaps_port)
end
def test_send_invalid_number
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
sock.gets
sock.print("RUBY0001 OK TEST completed\r\n")
sock.gets
sock.print("RUBY0002 OK TEST completed\r\n")
sock.gets
sock.print("RUBY0003 OK TEST completed\r\n")
sock.gets
sock.print("RUBY0004 OK TEST completed\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0005 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
assert_raise(Net::IMAP::DataFormatError) do
imap.__send__(:send_command, "TEST", -1)
end
imap.__send__(:send_command, "TEST", 0)
imap.__send__(:send_command, "TEST", 4294967295)
assert_raise(Net::IMAP::DataFormatError) do
imap.__send__(:send_command, "TEST", 4294967296)
end
assert_raise(Net::IMAP::DataFormatError) do
imap.__send__(:send_command, "TEST", Net::IMAP::MessageSet.new(-1))
end
assert_raise(Net::IMAP::DataFormatError) do
imap.__send__(:send_command, "TEST", Net::IMAP::MessageSet.new(0))
end
imap.__send__(:send_command, "TEST", Net::IMAP::MessageSet.new(1))
imap.__send__(:send_command, "TEST", Net::IMAP::MessageSet.new(4294967295))
assert_raise(Net::IMAP::DataFormatError) do
imap.__send__(:send_command, "TEST", Net::IMAP::MessageSet.new(4294967296))
end
imap.logout
ensure
imap.disconnect
end
end
def test_send_literal
server = create_tcp_server
port = server.addr[1]
requests = []
literal = nil
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
line = sock.gets
requests.push(line)
size = line.slice(/{(\d+)}\r\n/, 1).to_i
sock.print("+ Ready for literal data\r\n")
literal = sock.read(size)
requests.push(sock.gets)
sock.print("RUBY0001 OK TEST completed\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
imap.__send__(:send_command, "TEST", ["\xDE\xAD\xBE\xEF".b])
assert_equal(2, requests.length)
assert_equal("RUBY0001 TEST ({4}\r\n", requests[0])
assert_equal("\xDE\xAD\xBE\xEF".b, literal)
assert_equal(")\r\n", requests[1])
imap.logout
ensure
imap.disconnect
end
end
def test_disconnect
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0001 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
imap.logout
imap.disconnect
assert_equal(true, imap.disconnected?)
imap.disconnect
assert_equal(true, imap.disconnected?)
ensure
imap.disconnect if imap && !imap.disconnected?
end
end
def test_append
server = create_tcp_server
port = server.addr[1]
mail = <<EOF.gsub(/\n/, "\r\n")
From: shugo@example.com
To: matz@example.com
Subject: hello
hello world
EOF
requests = []
received_mail = nil
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
line = sock.gets
requests.push(line)
size = line.slice(/{(\d+)}\r\n/, 1).to_i
sock.print("+ Ready for literal data\r\n")
received_mail = sock.read(size)
sock.gets
sock.print("RUBY0001 OK APPEND completed\r\n")
requests.push(sock.gets)
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
imap.append("INBOX", mail)
assert_equal(1, requests.length)
assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
assert_equal(mail, received_mail)
imap.logout
assert_equal(2, requests.length)
assert_equal("RUBY0002 LOGOUT\r\n", requests[1])
ensure
imap.disconnect if imap
end
end
def test_append_fail
server = create_tcp_server
port = server.addr[1]
mail = <<EOF.gsub(/\n/, "\r\n")
From: shugo@example.com
To: matz@example.com
Subject: hello
hello world
EOF
requests = []
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
requests.push(sock.gets)
sock.print("RUBY0001 NO Mailbox doesn't exist\r\n")
requests.push(sock.gets)
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
assert_raise(Net::IMAP::NoResponseError) do
imap.append("INBOX", mail)
end
assert_equal(1, requests.length)
assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
imap.logout
assert_equal(2, requests.length)
assert_equal("RUBY0002 LOGOUT\r\n", requests[1])
ensure
imap.disconnect if imap
end
end
def test_id
server = create_tcp_server
port = server.addr[1]
requests = Queue.new
server_id = {"name" => "test server", "version" => "v0.1.0"}
server_id_str = '("name" "test server" "version" "v0.1.0")'
@threads << Thread.start do
sock = server.accept
begin
sock.print("* OK test server\r\n")
requests.push(sock.gets)
# RFC 2971 very clearly states (in section 3.2):
# "a server MUST send a tagged ID response to an ID command."
# And yet... some servers report ID capability but won't the response.
sock.print("RUBY0001 OK ID completed\r\n")
requests.push(sock.gets)
sock.print("* ID #{server_id_str}\r\n")
sock.print("RUBY0002 OK ID completed\r\n")
requests.push(sock.gets)
sock.print("* ID #{server_id_str}\r\n")
sock.print("RUBY0003 OK ID completed\r\n")
requests.push(sock.gets)
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0004 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = Net::IMAP.new(server_addr, :port => port)
resp = imap.id
assert_equal(nil, resp)
assert_equal("RUBY0001 ID NIL\r\n", requests.pop)
resp = imap.id({})
assert_equal(server_id, resp)
assert_equal("RUBY0002 ID ()\r\n", requests.pop)
resp = imap.id("name" => "test client", "version" => "latest")
assert_equal(server_id, resp)
assert_equal("RUBY0003 ID (\"name\" \"test client\" \"version\" \"latest\")\r\n",
requests.pop)
imap.logout
assert_equal("RUBY0004 LOGOUT\r\n", requests.pop)
ensure
imap.disconnect if imap
end
end
private
def imaps_test
server = create_tcp_server
port = server.addr[1]
ctx = OpenSSL::SSL::SSLContext.new
ctx.ca_file = CA_FILE
ctx.key = File.open(SERVER_KEY) { |f|
OpenSSL::PKey::RSA.new(f)
}
ctx.cert = File.open(SERVER_CERT) { |f|
OpenSSL::X509::Certificate.new(f)
}
ssl_server = OpenSSL::SSL::SSLServer.new(server, ctx)
started = false
ths = Thread.start do
Thread.current.report_on_exception = false # always join-ed
begin
started = true
sock = ssl_server.accept
begin
sock.print("* OK test server\r\n")
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0001 OK LOGOUT completed\r\n")
ensure
sock.close
end
rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
end
end
sleep 0.1 until started
begin
begin
imap = yield(port)
imap.logout
ensure
imap.disconnect if imap
end
ensure
ssl_server.close
ths.join
end
end
def starttls_test
server = create_tcp_server
port = server.addr[1]
start_server do
sock = server.accept
begin
sock.print("* OK test server\r\n")
sock.gets
sock.print("RUBY0001 OK completed\r\n")
ctx = OpenSSL::SSL::SSLContext.new
ctx.ca_file = CA_FILE
ctx.key = File.open(SERVER_KEY) { |f|
OpenSSL::PKey::RSA.new(f)
}
ctx.cert = File.open(SERVER_CERT) { |f|
OpenSSL::X509::Certificate.new(f)
}
sock = OpenSSL::SSL::SSLSocket.new(sock, ctx)
sock.sync_close = true
sock.accept
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
ensure
sock.close
server.close
end
end
begin
imap = yield(port)
imap.logout if !imap.disconnected?
ensure
imap.disconnect if imap && !imap.disconnected?
end
end
def create_tcp_server
return TCPServer.new(server_addr, 0)
end
def server_addr
Addrinfo.tcp("localhost", 0).ip_address
end
end

Просмотреть файл

@ -1,23 +0,0 @@
# frozen_string_literal: true
require "net/imap"
require "test/unit"
class IMAPAuthenticatorsTest < Test::Unit::TestCase
PLAIN = Net::IMAP::PlainAuthenticator
def test_plain
assert_equal("\0authc\0passwd",
PLAIN.new("authc", "passwd").process(nil))
assert_equal("authz\0user\0pass",
PLAIN.new("user", "pass", authzid: "authz").process(nil))
end
def test_plain_no_null_chars
assert_raise(ArgumentError) { PLAIN.new("bad\0user", "pass") }
assert_raise(ArgumentError) { PLAIN.new("user", "bad\0pass") }
assert_raise(ArgumentError) { PLAIN.new("u", "p", authzid: "bad\0authz") }
end
end

Просмотреть файл

@ -1,46 +0,0 @@
# frozen_string_literal: true
require "net/imap"
require "test/unit"
class IMAPDataEncodingTest < Test::Unit::TestCase
def test_encode_utf7
assert_equal("foo", Net::IMAP.encode_utf7("foo"))
assert_equal("&-", Net::IMAP.encode_utf7("&"))
utf8 = "\357\274\241\357\274\242\357\274\243".dup.force_encoding("UTF-8")
s = Net::IMAP.encode_utf7(utf8)
assert_equal("&,yH,Iv8j-", s)
s = Net::IMAP.encode_utf7("foo&#{utf8}-bar".encode("EUC-JP"))
assert_equal("foo&-&,yH,Iv8j--bar", s)
utf8 = "\343\201\202&".dup.force_encoding("UTF-8")
s = Net::IMAP.encode_utf7(utf8)
assert_equal("&MEI-&-", s)
s = Net::IMAP.encode_utf7(utf8.encode("EUC-JP"))
assert_equal("&MEI-&-", s)
end
def test_decode_utf7
assert_equal("&", Net::IMAP.decode_utf7("&-"))
assert_equal("&-", Net::IMAP.decode_utf7("&--"))
s = Net::IMAP.decode_utf7("&,yH,Iv8j-")
utf8 = "\357\274\241\357\274\242\357\274\243".dup.force_encoding("UTF-8")
assert_equal(utf8, s)
end
def test_format_date
time = Time.mktime(2009, 7, 24)
s = Net::IMAP.format_date(time)
assert_equal("24-Jul-2009", s)
end
def test_format_datetime
time = Time.mktime(2009, 7, 24, 1, 23, 45)
s = Net::IMAP.format_datetime(time)
assert_match(/\A24-Jul-2009 01:23 [+\-]\d{4}\z/, s)
end
end

Просмотреть файл

@ -1,389 +0,0 @@
# frozen_string_literal: true
require "net/imap"
require "test/unit"
class IMAPResponseParserTest < Test::Unit::TestCase
def setup
@do_not_reverse_lookup = Socket.do_not_reverse_lookup
Socket.do_not_reverse_lookup = true
if Net::IMAP.respond_to?(:max_flag_count)
@max_flag_count = Net::IMAP.max_flag_count
Net::IMAP.max_flag_count = 3
end
end
def teardown
Socket.do_not_reverse_lookup = @do_not_reverse_lookup
if Net::IMAP.respond_to?(:max_flag_count)
Net::IMAP.max_flag_count = @max_flag_count
end
end
def test_flag_list_too_many_flags
parser = Net::IMAP::ResponseParser.new
assert_nothing_raised do
3.times do |i|
parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* LIST (\\Foo#{i}) "." "INBOX"
EOF
end
end
assert_raise(Net::IMAP::FlagCountError) do
parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* LIST (\\Foo3) "." "INBOX"
EOF
end
end
def test_flag_list_many_same_flags
parser = Net::IMAP::ResponseParser.new
assert_nothing_raised do
100.times do
parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* LIST (\\Foo) "." "INBOX"
EOF
end
end
end
def test_flag_xlist_inbox
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* XLIST (\\Inbox) "." "INBOX"
EOF
assert_equal [:Inbox], response.data.attr
end
def test_resp_text_code
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* OK [CLOSED] Previous mailbox closed.
EOF
assert_equal "CLOSED", response.data.code.name
end
def test_search_response
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* SEARCH
EOF
assert_equal [], response.data
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* SEARCH 1
EOF
assert_equal [1], response.data
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* SEARCH 1 2 3
EOF
assert_equal [1, 2, 3], response.data
end
def test_search_response_of_yahoo
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* SEARCH 1\s
EOF
assert_equal [1], response.data
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* SEARCH 1 2 3\s
EOF
assert_equal [1, 2, 3], response.data
end
def test_msg_att_extra_space
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 1 FETCH (UID 92285)
EOF
assert_equal 92285, response.data.attr["UID"]
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 1 FETCH (UID 92285 )
EOF
assert_equal 92285, response.data.attr["UID"]
end
def test_msg_att_parse_error
parser = Net::IMAP::ResponseParser.new
e = assert_raise(Net::IMAP::ResponseParseError) {
parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 123 FETCH (UNKNOWN 92285)
EOF
}
assert_match(/ for \{123\}/, e.message)
end
def test_msg_att_rfc822_text
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 123 FETCH (RFC822 {5}
foo
)
EOF
assert_equal("foo\r\n", response.data.attr["RFC822"])
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 123 FETCH (RFC822[] {5}
foo
)
EOF
assert_equal("foo\r\n", response.data.attr["RFC822"])
end
# [Bug #6397] [ruby-core:44849]
def test_body_type_attachment
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 980 FETCH (UID 2862 BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "7BIT" 416 21 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "7BIT" 1493 32 NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "Boundary_(ID_IaecgfnXwG5bn3x8lIeGIQ)") NIL NIL)("MESSAGE" "RFC822" ("NAME" "Fw_ ____ _____ ____.eml") NIL NIL "7BIT" 1980088 NIL ("ATTACHMENT" ("FILENAME" "Fw_ ____ _____ ____.eml")) NIL) "MIXED" ("BOUNDARY" "Boundary_(ID_eDdLc/j0mBIzIlR191pHjA)") NIL NIL))
EOF
assert_equal("Fw_ ____ _____ ____.eml",
response.data.attr["BODYSTRUCTURE"].parts[1].body.param["FILENAME"])
end
def assert_parseable(s)
parser = Net::IMAP::ResponseParser.new
parser.parse(s.gsub(/\n/, "\r\n"))
end
# [Bug #7146]
def test_msg_delivery_status
# This was part of a larger response that caused crashes, but this was the
# minimal test case to demonstrate it
assert_parseable <<EOF
* 4902 FETCH (BODY (("MESSAGE" "DELIVERY-STATUS" NIL NIL NIL "7BIT" 324) "REPORT"))
EOF
end
# [Bug #7147]
def test_msg_with_message_rfc822_attachment
assert_parseable <<EOF
* 5441 FETCH (BODY ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 69 1)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 455 12) "ALTERNATIVE")("MESSAGE" "RFC822" ("NAME" "ATT00026.eml") NIL NIL "7BIT" 4079755) "MIXED"))
EOF
end
# [Bug #7153]
def test_msg_body_mixed
assert_parseable <<EOF
* 1038 FETCH (BODY ("MIXED"))
EOF
end
# [Bug #8167]
def test_msg_delivery_status_with_extra_data
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* 29021 FETCH (RFC822.SIZE 3162 UID 113622 RFC822.HEADER {1155}
Return-path: <>
Envelope-to: info@xxxxxxxx.si
Delivery-date: Tue, 26 Mar 2013 12:42:58 +0100
Received: from mail by xxxx.xxxxxxxxxxx.net with spam-scanned (Exim 4.76)
id 1UKSHI-000Cwl-AR
for info@xxxxxxxx.si; Tue, 26 Mar 2013 12:42:58 +0100
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on xxxx.xxxxxxxxxxx.net
X-Spam-Level: **
X-Spam-Status: No, score=2.1 required=7.0 tests=DKIM_ADSP_NXDOMAIN,RDNS_NONE
autolearn=no version=3.3.1
Received: from [xx.xxx.xxx.xx] (port=56890 helo=xxxxxx.localdomain)
by xxxx.xxxxxxxxxxx.net with esmtp (Exim 4.76)
id 1UKSHI-000Cwi-9j
for info@xxxxxxxx.si; Tue, 26 Mar 2013 12:42:56 +0100
Received: by xxxxxx.localdomain (Postfix)
id 72725BEA64A; Tue, 26 Mar 2013 12:42:55 +0100 (CET)
Date: Tue, 26 Mar 2013 12:42:55 +0100 (CET)
From: MAILER-DAEMON@xxxxxx.localdomain (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
To: info@xxxxxxxx.si
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="27797BEA649.1364298175/xxxxxx.localdomain"
Message-Id: <20130326114255.72725BEA64A@xxxxxx.localdomain>
BODYSTRUCTURE (("text" "plain" ("charset" "us-ascii") NIL "Notification" "7bit" 510 14 NIL NIL NIL NIL)("message" "delivery-status" NIL NIL "Delivery report" "7bit" 410 NIL NIL NIL NIL)("text" "rfc822-headers" ("charset" "us-ascii") NIL "Undelivered Message Headers" "7bit" 612 15 NIL NIL NIL NIL) "report" ("report-type" "delivery-status" "boundary" "27797BEA649.1364298175/xxxxxx.localdomain") NIL NIL NIL))
EOF
delivery_status = response.data.attr["BODYSTRUCTURE"].parts[1]
assert_equal("MESSAGE", delivery_status.media_type)
assert_equal("DELIVERY-STATUS", delivery_status.subtype)
assert_equal(nil, delivery_status.param)
assert_equal(nil, delivery_status.content_id)
assert_equal("Delivery report", delivery_status.description)
assert_equal("7BIT", delivery_status.encoding)
assert_equal(410, delivery_status.size)
end
# [Bug #8281]
def test_acl
parser = Net::IMAP::ResponseParser.new
response = parser.parse(<<EOF.gsub(/\n/, "\r\n"))
* ACL "INBOX/share" "imshare2copy1366146467@xxxxxxxxxxxxxxxxxx.com" lrswickxteda
EOF
assert_equal("ACL", response.name)
assert_equal(1, response.data.length)
assert_equal("INBOX/share", response.data[0].mailbox)
assert_equal("imshare2copy1366146467@xxxxxxxxxxxxxxxxxx.com",
response.data[0].user)
assert_equal("lrswickxteda", response.data[0].rights)
end
# [Bug #8415]
def test_capability
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* CAPABILITY st11p00mm-iscream009 1Q49 XAPPLEPUSHSERVICE IMAP4 IMAP4rev1 SASL-IR AUTH=ATOKEN AUTH=PLAIN\r\n")
assert_equal("CAPABILITY", response.name)
assert_equal("AUTH=PLAIN", response.data.last)
response = parser.parse("* CAPABILITY st11p00mm-iscream009 1Q49 XAPPLEPUSHSERVICE IMAP4 IMAP4rev1 SASL-IR AUTH=ATOKEN AUTH=PLAIN \r\n")
assert_equal("CAPABILITY", response.name)
assert_equal("AUTH=PLAIN", response.data.last)
response = parser.parse("* OK [CAPABILITY IMAP4rev1 SASL-IR 1234 NIL THIS+THAT + AUTH=PLAIN ID] IMAP4rev1 Hello\r\n")
assert_equal("OK", response.name)
assert_equal("IMAP4rev1 Hello", response.data.text)
code = response.data.code
assert_equal("CAPABILITY", code.name)
assert_equal(
["IMAP4REV1", "SASL-IR", "1234", "NIL", "THIS+THAT", "+", "AUTH=PLAIN", "ID"],
code.data
)
end
def test_id
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* ID NIL\r\n")
assert_equal("ID", response.name)
assert_equal(nil, response.data)
response = parser.parse("* ID (\"name\" \"GImap\" \"vendor\" \"Google, Inc.\" \"support-url\" NIL)\r\n")
assert_equal("ID", response.name)
assert_equal("GImap", response.data["name"])
assert_equal("Google, Inc.", response.data["vendor"])
assert_equal(nil, response.data.fetch("support-url"))
end
def test_mixed_boundary
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* 2688 FETCH (UID 179161 BODYSTRUCTURE (" \
"(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"iso-8859-1\") NIL NIL \"QUOTED-PRINTABLE\" 200 4 NIL NIL NIL)" \
"(\"MESSAGE\" \"DELIVERY-STATUS\" NIL NIL NIL \"7BIT\" 318 NIL NIL NIL)" \
"(\"MESSAGE\" \"RFC822\" NIL NIL NIL \"7BIT\" 2177" \
" (\"Tue, 11 May 2010 18:28:16 -0400\" \"Re: Welcome letter\" (" \
"(\"David\" NIL \"info\" \"xxxxxxxx.si\")) " \
"((\"David\" NIL \"info\" \"xxxxxxxx.si\")) " \
"((\"David\" NIL \"info\" \"xxxxxxxx.si\")) " \
"((\"Doretha\" NIL \"doretha.info\" \"xxxxxxxx.si\")) " \
"NIL NIL " \
"\"<AC1D15E06EA82F47BDE18E851CC32F330717704E@localdomain>\" " \
"\"<AANLkTikKMev1I73L2E7XLjRs67IHrEkb23f7ZPmD4S_9@localdomain>\")" \
" (\"MIXED\" (\"BOUNDARY\" \"000e0cd29212e3e06a0486590ae2\") NIL NIL)" \
" 37 NIL NIL NIL)" \
" \"REPORT\" (\"BOUNDARY\" \"16DuG.4XbaNOvCi.9ggvq.8Ipnyp3\" \"REPORT-TYPE\" \"delivery-status\") NIL NIL))\r\n")
empty_part = response.data.attr['BODYSTRUCTURE'].parts[2]
assert_equal(empty_part.lines, 37)
assert_equal(empty_part.body.media_type, 'MULTIPART')
assert_equal(empty_part.body.subtype, 'MIXED')
assert_equal(empty_part.body.param['BOUNDARY'], '000e0cd29212e3e06a0486590ae2')
end
# [Bug #10112]
def test_search_modseq
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* SEARCH 87216 87221 (MODSEQ 7667567)\r\n")
assert_equal("SEARCH", response.name)
assert_equal([87216, 87221], response.data)
end
# [Bug #11128]
def test_body_ext_mpart_without_lang
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* 4 FETCH (BODY (((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 257 9 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"quoted-printable\" 655 9 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"001a1137a5047848dd05157ddaa1\") NIL)(\"application\" \"pdf\" (\"name\" \"test.xml\" \"x-apple-part-url\" \"9D00D9A2-98AB-4EFB-85BA-FB255F8BF3D7\") NIL NIL \"base64\" 4383638 NIL (\"attachment\" (\"filename\" \"test.xml\")) NIL NIL) \"mixed\" (\"boundary\" \"001a1137a5047848e405157ddaa3\") NIL))\r\n")
assert_equal("FETCH", response.name)
body = response.data.attr["BODY"]
assert_equal(nil, body.parts[0].disposition)
assert_equal(nil, body.parts[0].language)
assert_equal("ATTACHMENT", body.parts[1].disposition.dsp_type)
assert_equal("test.xml", body.parts[1].disposition.param["FILENAME"])
assert_equal(nil, body.parts[1].language)
end
# [Bug #13649]
def test_status
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* STATUS INBOX (UIDNEXT 1 UIDVALIDITY 1234)\r\n")
assert_equal("STATUS", response.name)
assert_equal("INBOX", response.data.mailbox)
assert_equal(1234, response.data.attr["UIDVALIDITY"])
response = parser.parse("* STATUS INBOX (UIDNEXT 1 UIDVALIDITY 1234) \r\n")
assert_equal("STATUS", response.name)
assert_equal("INBOX", response.data.mailbox)
assert_equal(1234, response.data.attr["UIDVALIDITY"])
end
# [Bug #10119]
def test_msg_att_modseq_data
parser = Net::IMAP::ResponseParser.new
response = parser.parse("* 1 FETCH (FLAGS (\Seen) MODSEQ (12345) UID 5)\r\n")
assert_equal(12345, response.data.attr["MODSEQ"])
end
def test_msg_rfc3501_response_text_with_T_LBRA
parser = Net::IMAP::ResponseParser.new
response = parser.parse("RUBY0004 OK [READ-WRITE] [Gmail]/Sent Mail selected. (Success)\r\n")
assert_equal("RUBY0004", response.tag)
assert_equal("READ-WRITE", response.data.code.name)
assert_equal("[Gmail]/Sent Mail selected. (Success)", response.data.text)
end
def test_msg_rfc3501_response_text_with_BADCHARSET_astrings
parser = Net::IMAP::ResponseParser.new
response = parser.parse("t BAD [BADCHARSET (US-ASCII \"[astring with brackets]\")] unsupported charset foo.\r\n")
assert_equal("t", response.tag)
assert_equal("unsupported charset foo.", response.data.text)
assert_equal("BADCHARSET", response.data.code.name)
end
def test_continuation_request_without_response_text
parser = Net::IMAP::ResponseParser.new
response = parser.parse("+\r\n")
assert_instance_of(Net::IMAP::ContinuationRequest, response)
assert_equal(nil, response.data.code)
assert_equal("", response.data.text)
end
def test_ignored_response
parser = Net::IMAP::ResponseParser.new
response = nil
assert_nothing_raised do
response = parser.parse("* NOOP\r\n")
end
assert_instance_of(Net::IMAP::IgnoredResponse, response)
end
def test_namespace
parser = Net::IMAP::ResponseParser.new
# RFC2342 Example 5.1
response = parser.parse(%Q{* NAMESPACE (("" "/")) NIL NIL\r\n})
assert_equal("NAMESPACE", response.name)
assert_equal([Net::IMAP::Namespace.new("", "/", {})], response.data.personal)
assert_equal([], response.data.other)
assert_equal([], response.data.shared)
# RFC2342 Example 5.4
response = parser.parse(%Q{* NAMESPACE (("" "/")) (("~" "/")) (("#shared/" "/")} +
%Q{ ("#public/" "/") ("#ftp/" "/") ("#news." "."))\r\n})
assert_equal("NAMESPACE", response.name)
assert_equal([Net::IMAP::Namespace.new("", "/", {})], response.data.personal)
assert_equal([Net::IMAP::Namespace.new("~", "/", {})], response.data.other)
assert_equal(
[
Net::IMAP::Namespace.new("#shared/", "/", {}),
Net::IMAP::Namespace.new("#public/", "/", {}),
Net::IMAP::Namespace.new("#ftp/", "/", {}),
Net::IMAP::Namespace.new("#news.", ".", {}),
],
response.data.shared
)
# RFC2342 Example 5.6
response = parser.parse(%Q{* NAMESPACE (("" "/") ("#mh/" "/" "X-PARAM" ("FLAG1" "FLAG2"))) NIL NIL\r\n})
assert_equal("NAMESPACE", response.name)
namespace = response.data.personal.last
assert_equal("#mh/", namespace.prefix)
assert_equal("/", namespace.delim)
assert_equal({"X-PARAM" => ["FLAG1", "FLAG2"]}, namespace.extensions)
end
end

Просмотреть файл

@ -51,7 +51,6 @@ REPOSITORIES = {
tmpdir: "ruby/tmpdir",
English: "ruby/English",
"net-protocol": "ruby/net-protocol",
"net-imap": "ruby/net-imap",
"net-http": "ruby/net-http",
bigdecimal: "ruby/bigdecimal",
optparse: "ruby/optparse",
@ -260,12 +259,6 @@ def sync_default_gems(gem)
cp_r("#{upstream}/lib/net/protocol.rb", "lib/net")
cp_r("#{upstream}/test/net/protocol", "test/net")
cp_r("#{upstream}/net-protocol.gemspec", "lib/net")
when "net-imap"
rm_rf(%w[lib/net/imap.rb lib/net/imap test/net/imap])
cp_r("#{upstream}/lib/net/imap.rb", "lib/net")
cp_r("#{upstream}/lib/net/imap", "lib/net")
cp_r("#{upstream}/test/net/imap", "test/net")
cp_r("#{upstream}/net-imap.gemspec", "lib/net/imap")
when "net-http"
rm_rf(%w[lib/net/http.rb lib/net/http test/net/http])
cp_r("#{upstream}/lib/net/http.rb", "lib/net")