summaryrefslogtreecommitdiff
path: root/jni/ruby/test/net/imap
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/test/net/imap
Fresh start
Diffstat (limited to 'jni/ruby/test/net/imap')
-rw-r--r--jni/ruby/test/net/imap/Makefile15
-rw-r--r--jni/ruby/test/net/imap/cacert.pem66
-rw-r--r--jni/ruby/test/net/imap/server.crt48
-rw-r--r--jni/ruby/test/net/imap/server.key15
-rw-r--r--jni/ruby/test/net/imap/test_imap.rb550
-rw-r--r--jni/ruby/test/net/imap/test_imap_response_parser.rb292
6 files changed, 986 insertions, 0 deletions
diff --git a/jni/ruby/test/net/imap/Makefile b/jni/ruby/test/net/imap/Makefile
new file mode 100644
index 0000000..b2bc9c7
--- /dev/null
+++ b/jni/ruby/test/net/imap/Makefile
@@ -0,0 +1,15 @@
+all:
+
+regen_certs:
+ touch server.key
+ make server.crt
+
+cacert.pem: server.key
+ openssl req -new -x509 -days 1825 -key server.key -out cacert.pem -text -subj "/C=JP/ST=Shimane/L=Matz-e city/O=Ruby Core Team/CN=Ruby Test CA/emailAddress=security@ruby-lang.org"
+
+server.csr:
+ openssl req -new -key server.key -out server.csr -text -subj "/C=JP/ST=Shimane/O=Ruby Core Team/OU=Ruby Test/CN=localhost"
+
+server.crt: server.csr cacert.pem
+ openssl x509 -days 1825 -CA cacert.pem -CAkey server.key -set_serial 00 -in server.csr -req -text -out server.crt
+ rm server.csr
diff --git a/jni/ruby/test/net/imap/cacert.pem b/jni/ruby/test/net/imap/cacert.pem
new file mode 100644
index 0000000..7073387
--- /dev/null
+++ b/jni/ruby/test/net/imap/cacert.pem
@@ -0,0 +1,66 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ b9:90:a2:bf:62:69:17:9c
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org
+ Validity
+ Not Before: Jan 3 01:34:17 2014 GMT
+ Not After : Jan 2 01:34:17 2019 GMT
+ Subject: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:db:75:d0:45:de:b1:df:bf:71:a0:0e:b0:a5:e6:
+ bc:f4:1c:9d:e5:25:67:64:c5:7b:cb:f1:af:c6:be:
+ 9a:aa:ea:7e:0f:cc:05:af:ef:40:69:06:b2:c9:13:
+ 9d:7e:eb:a2:06:e2:ea:7d:07:c7:c7:99:c7:fb:d5:
+ b8:eb:63:77:62:2b:18:12:c3:53:58:d0:f5:c7:40:
+ 0c:01:d1:26:82:34:16:09:e3:dc:65:f4:dc:bb:5d:
+ a5:41:60:e7:a9:74:ba:d7:4c:b6:a3:9c:c5:8c:89:
+ af:cb:e8:9f:05:fe:ea:fe:64:24:bf:e7:ed:e3:f6:
+ d0:fc:d6:eb:fc:06:82:10:fb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ E8:7E:58:AC:13:7B:03:22:8D:9E:AF:32:0B:84:89:80:80:0C:1E:C2
+ X509v3 Authority Key Identifier:
+ keyid:E8:7E:58:AC:13:7B:03:22:8D:9E:AF:32:0B:84:89:80:80:0C:1E:C2
+ DirName:/C=JP/ST=Shimane/L=Matz-e city/O=Ruby Core Team/CN=Ruby Test CA/emailAddress=security@ruby-lang.org
+ serial:B9:90:A2:BF:62:69:17:9C
+
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ 8f:77:06:4e:31:72:12:ee:68:09:70:27:d4:31:85:ef:10:95:
+ f9:0f:2b:66:63:08:37:88:6e:b7:9b:40:3e:18:77:33:86:e8:
+ 61:6a:b7:3c:cb:c7:a6:d6:d5:92:6a:1f:56:d0:9f:5c:32:56:
+ d3:37:52:fe:0e:20:c2:7a:0d:fe:2d:3c:81:da:b8:7f:4d:6a:
+ 08:01:d9:be:7a:a2:15:be:a6:ce:49:64:90:8c:9a:ca:6e:2e:
+ 84:48:1d:94:19:56:94:46:aa:25:9b:68:c2:80:60:bf:cb:2e:
+ 35:03:ea:0a:65:5a:33:38:c6:cc:81:46:c0:bc:36:86:96:39:
+ 10:7d
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAvagAwIBAgIJALmQor9iaRecMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD
+VQQGEwJKUDEQMA4GA1UECBMHU2hpbWFuZTEUMBIGA1UEBxMLTWF0ei1lIGNpdHkx
+FzAVBgNVBAoTDlJ1YnkgQ29yZSBUZWFtMRUwEwYDVQQDEwxSdWJ5IFRlc3QgQ0Ex
+JTAjBgkqhkiG9w0BCQEWFnNlY3VyaXR5QHJ1YnktbGFuZy5vcmcwHhcNMTQwMTAz
+MDEzNDE3WhcNMTkwMTAyMDEzNDE3WjCBjDELMAkGA1UEBhMCSlAxEDAOBgNVBAgT
+B1NoaW1hbmUxFDASBgNVBAcTC01hdHotZSBjaXR5MRcwFQYDVQQKEw5SdWJ5IENv
+cmUgVGVhbTEVMBMGA1UEAxMMUnVieSBUZXN0IENBMSUwIwYJKoZIhvcNAQkBFhZz
+ZWN1cml0eUBydWJ5LWxhbmcub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQDbddBF3rHfv3GgDrCl5rz0HJ3lJWdkxXvL8a/Gvpqq6n4PzAWv70BpBrLJE51+
+66IG4up9B8fHmcf71bjrY3diKxgSw1NY0PXHQAwB0SaCNBYJ49xl9Ny7XaVBYOep
+dLrXTLajnMWMia/L6J8F/ur+ZCS/5+3j9tD81uv8BoIQ+wIDAQABo4H0MIHxMB0G
+A1UdDgQWBBToflisE3sDIo2erzILhImAgAwewjCBwQYDVR0jBIG5MIG2gBToflis
+E3sDIo2erzILhImAgAwewqGBkqSBjzCBjDELMAkGA1UEBhMCSlAxEDAOBgNVBAgT
+B1NoaW1hbmUxFDASBgNVBAcTC01hdHotZSBjaXR5MRcwFQYDVQQKEw5SdWJ5IENv
+cmUgVGVhbTEVMBMGA1UEAxMMUnVieSBUZXN0IENBMSUwIwYJKoZIhvcNAQkBFhZz
+ZWN1cml0eUBydWJ5LWxhbmcub3JnggkAuZCiv2JpF5wwDAYDVR0TBAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOBgQCPdwZOMXIS7mgJcCfUMYXvEJX5DytmYwg3iG63m0A+
+GHczhuhharc8y8em1tWSah9W0J9cMlbTN1L+DiDCeg3+LTyB2rh/TWoIAdm+eqIV
+vqbOSWSQjJrKbi6ESB2UGVaURqolm2jCgGC/yy41A+oKZVozOMbMgUbAvDaGljkQ
+fQ==
+-----END CERTIFICATE-----
diff --git a/jni/ruby/test/net/imap/server.crt b/jni/ruby/test/net/imap/server.crt
new file mode 100644
index 0000000..fa4f994
--- /dev/null
+++ b/jni/ruby/test/net/imap/server.crt
@@ -0,0 +1,48 @@
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org
+ Validity
+ Not Before: Jan 3 01:34:17 2014 GMT
+ Not After : Jan 2 01:34:17 2019 GMT
+ Subject: C=JP, ST=Shimane, O=Ruby Core Team, OU=Ruby Test, CN=localhost
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:db:75:d0:45:de:b1:df:bf:71:a0:0e:b0:a5:e6:
+ bc:f4:1c:9d:e5:25:67:64:c5:7b:cb:f1:af:c6:be:
+ 9a:aa:ea:7e:0f:cc:05:af:ef:40:69:06:b2:c9:13:
+ 9d:7e:eb:a2:06:e2:ea:7d:07:c7:c7:99:c7:fb:d5:
+ b8:eb:63:77:62:2b:18:12:c3:53:58:d0:f5:c7:40:
+ 0c:01:d1:26:82:34:16:09:e3:dc:65:f4:dc:bb:5d:
+ a5:41:60:e7:a9:74:ba:d7:4c:b6:a3:9c:c5:8c:89:
+ af:cb:e8:9f:05:fe:ea:fe:64:24:bf:e7:ed:e3:f6:
+ d0:fc:d6:eb:fc:06:82:10:fb
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha1WithRSAEncryption
+ 85:f5:d3:05:8b:8c:f4:43:1c:88:f2:8f:b2:f2:93:77:b7:3d:
+ 95:c6:a0:34:bc:33:6a:d8:85:5f:3e:86:08:10:c5:5c:c1:76:
+ a3:53:3c:dc:38:98:23:97:e7:da:21:ac:e8:4d:3c:96:70:29:
+ ff:ff:1e:4a:9a:17:2b:db:04:62:b9:ef:ab:ea:a7:a5:e8:7c:
+ b1:d5:ed:30:a8:6c:78:de:51:7e:e3:8a:c2:a4:64:a8:63:a2:
+ bc:fd:43:9c:f3:55:7d:54:c9:6a:d8:53:1c:4b:6b:03:aa:b6:
+ 19:e6:a4:4f:47:00:96:c5:42:59:85:4e:c3:4e:cd:41:82:53:
+ 10:f8
+-----BEGIN CERTIFICATE-----
+MIICXDCCAcUCAQAwDQYJKoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAkpQMRAwDgYD
+VQQIEwdTaGltYW5lMRQwEgYDVQQHEwtNYXR6LWUgY2l0eTEXMBUGA1UEChMOUnVi
+eSBDb3JlIFRlYW0xFTATBgNVBAMTDFJ1YnkgVGVzdCBDQTElMCMGCSqGSIb3DQEJ
+ARYWc2VjdXJpdHlAcnVieS1sYW5nLm9yZzAeFw0xNDAxMDMwMTM0MTdaFw0xOTAx
+MDIwMTM0MTdaMGAxCzAJBgNVBAYTAkpQMRAwDgYDVQQIEwdTaGltYW5lMRcwFQYD
+VQQKEw5SdWJ5IENvcmUgVGVhbTESMBAGA1UECxMJUnVieSBUZXN0MRIwEAYDVQQD
+Ewlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANt10EXesd+/
+caAOsKXmvPQcneUlZ2TFe8vxr8a+mqrqfg/MBa/vQGkGsskTnX7rogbi6n0Hx8eZ
+x/vVuOtjd2IrGBLDU1jQ9cdADAHRJoI0Fgnj3GX03LtdpUFg56l0utdMtqOcxYyJ
+r8vonwX+6v5kJL/n7eP20PzW6/wGghD7AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA
+hfXTBYuM9EMciPKPsvKTd7c9lcagNLwzatiFXz6GCBDFXMF2o1M83DiYI5fn2iGs
+6E08lnAp//8eSpoXK9sEYrnvq+qnpeh8sdXtMKhseN5RfuOKwqRkqGOivP1DnPNV
+fVTJathTHEtrA6q2GeakT0cAlsVCWYVOw07NQYJTEPg=
+-----END CERTIFICATE-----
diff --git a/jni/ruby/test/net/imap/server.key b/jni/ruby/test/net/imap/server.key
new file mode 100644
index 0000000..7c57546
--- /dev/null
+++ b/jni/ruby/test/net/imap/server.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDbddBF3rHfv3GgDrCl5rz0HJ3lJWdkxXvL8a/Gvpqq6n4PzAWv
+70BpBrLJE51+66IG4up9B8fHmcf71bjrY3diKxgSw1NY0PXHQAwB0SaCNBYJ49xl
+9Ny7XaVBYOepdLrXTLajnMWMia/L6J8F/ur+ZCS/5+3j9tD81uv8BoIQ+wIDAQAB
+AoGAGtYHR+P5gFDaxiXFuCPFC1zMeg7e29XCU6gURIteQnQ2QhxCvcbV64HkLu51
+HeYWhB0Pa4aeCWxmpgb2e+JH4MEoIjeJSGyZQeqwkQLgWJDdvkgWx5am58QzA60I
+ipkZ9QHcPffSs5RiGx4yfr58KqAmwFphGCY8W7v4LqaENdECQQD9H5VTW9g4gj1c
+j3uNYvSI/D7a9P7gfI+ziczuwMm5xsBx3D/t5TAr3SJKNne3sl1E6ZERCUbzxf+C
+k58EiHx1AkEA3fRLGqDOq7EcQhbjTcA/v/t5MwlGEUsS9+XrqOWn50YuoIwRZJ3v
+qHRQzfQfFNklGtfBvwQ4md3irXjMeGVprwJBAMEAuwiDiHuV+xm/ofKtmE13IKot
+ksYy1BOOp/8IawhHXueyi+BmF/PqOkIiA+jCjNGF0oIN89beizPSQbbgJx0CQG/K
+qL1bu1ys0y/SeWBi8XkP/0aeaCUzq/UiYCTsrzoEll2UzvnftqMhGsXxLGqCyHaR
+r2s3hA6zvIVlL4+AfM8CQQClq+WDrC5VKciLYakZNWJjV1m+H2Ut/0fXdUjKHajE
+FWLcsrOhADf6bkTb71GwPxnKRkkRmud5upP0ZYYTqM4X
+-----END RSA PRIVATE KEY-----
diff --git a/jni/ruby/test/net/imap/test_imap.rb b/jni/ruby/test/net/imap/test_imap.rb
new file mode 100644
index 0000000..da33533
--- /dev/null
+++ b/jni/ruby/test/net/imap/test_imap.rb
@@ -0,0 +1,550 @@
+require "net/imap"
+require "test/unit"
+
+class IMAPTest < Test::Unit::TestCase
+ CA_FILE = File.expand_path("cacert.pem", File.dirname(__FILE__))
+ SERVER_KEY = File.expand_path("server.key", File.dirname(__FILE__))
+ SERVER_CERT = File.expand_path("server.crt", File.dirname(__FILE__))
+
+ SERVER_ADDR = "127.0.0.1"
+
+ 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
+
+ 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".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&".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".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
+
+ 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 test_unexpected_eof
+ server = create_tcp_server
+ port = server.addr[1]
+ @threads << Thread.start 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 = []
+ @threads << Thread.start 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 = []
+ @threads << Thread.start 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
+ @threads << Thread.start do
+ m.synchronize do
+ until in_idle
+ c.wait(0.1)
+ end
+ end
+ th.raise(Interrupt)
+ exception_raised = true
+ end
+ 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
+ end
+ end
+
+ def test_idle_done_not_during_idle
+ server = create_tcp_server
+ port = server.addr[1]
+ @threads << Thread.start do
+ sock = server.accept
+ begin
+ sock.print("* OK test server\r\n")
+ 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_unexpected_bye
+ server = create_tcp_server
+ port = server.addr[1]
+ @threads << Thread.start 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]
+ @threads << Thread.start 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 = []
+ threads << Thread.start do
+ 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
+ threads << Thread.start do
+ imap = Net::IMAP.new(SERVER_ADDR, :port => port)
+ begin
+ m = Monitor.new
+ in_idle = false
+ exception_raised = false
+ c = m.new_cond
+ threads << Thread.start do
+ m.synchronize do
+ until in_idle
+ c.wait(0.1)
+ end
+ end
+ sock.close
+ exception_raised = true
+ end
+ assert_raise(Net::IMAP::Error) do
+ imap.idle do |res|
+ m.synchronize do
+ in_idle = true
+ c.signal
+ until exception_raised
+ 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]
+ @threads << Thread.start do
+ begin
+ sock = server.accept
+ sock.close
+ ensure
+ server.close
+ end
+ end
+ assert_raise(Net::IMAP::Error) do
+ Net::IMAP.new(SERVER_ADDR, :port => port)
+ 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]
+ @threads << Thread.start 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
+
+ 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)
+ ths = Thread.start do
+ begin
+ 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
+ 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]
+ @threads << Thread.start 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
+end
diff --git a/jni/ruby/test/net/imap/test_imap_response_parser.rb b/jni/ruby/test/net/imap/test_imap_response_parser.rb
new file mode 100644
index 0000000..1612d78
--- /dev/null
+++ b/jni/ruby/test/net/imap/test_imap_response_parser.rb
@@ -0,0 +1,292 @@
+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_safe
+ parser = Net::IMAP::ResponseParser.new
+ response = lambda {
+ $SAFE = 1
+ parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* LIST (\\HasChildren) "." "INBOX"
+EOF
+ }.call
+ assert_equal [:Haschildren], response.data.attr
+ 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").taint)
+* LIST (\\Foo#{i}) "." "INBOX"
+EOF
+ end
+ end
+ assert_raise(Net::IMAP::FlagCountError) do
+ parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* 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").taint)
+* 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").taint)
+* 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").taint)
+* 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").taint)
+* SEARCH
+EOF
+ assert_equal [], response.data
+ response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* SEARCH 1
+EOF
+ assert_equal [1], response.data
+ response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* 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").taint)
+* SEARCH 1\s
+EOF
+ assert_equal [1], response.data
+ response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* 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").taint)
+* 1 FETCH (UID 92285)
+EOF
+ assert_equal 92285, response.data.attr["UID"]
+
+ response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* 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").taint)
+* 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").taint)
+* 123 FETCH (RFC822 {5}
+foo
+)
+EOF
+ assert_equal("foo\r\n", response.data.attr["RFC822"])
+ response = parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* 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").taint)
+* 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").taint)
+ 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").taint)
+* 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").taint)
+* 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)
+ end
+
+ def test_mixed_boundry
+ 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
+end